@tacman1123/collection-slider
v0.1.0
Published
A dependency-free, framework-agnostic value slider (Fortepan.hu-style year ruler) that drives a live-following thumbnail carousel (fortepan.us-style). Two custom elements, zero build step required.
Maintainers
Readme
@tacman1123/collection-slider
A dependency-free value slider (<collection-slider>, a Fortepan.hu-style year ruler with a
count badge) paired with a live-following thumbnail carousel (CollectionCarousel,
fortepan.us-style). Two plain custom elements / classes, zero build step, zero framework
requirement.
Trivial setup
No npm install required to try it — import straight from a CDN or a local copy as native ESM:
<script type="module">
import { CollectionCarousel } from 'https://unpkg.com/@tacman1123/collection-slider/index.js';
// importing collection-slider.js (directly or via the barrel) registers <collection-slider>
// as a side effect — no separate customElements.define() call needed.
</script>
<collection-slider min="1900" max="1988" value="1954"></collection-slider>
<div id="thumbnails"></div>
<img id="main-image" alt="">
<script type="module">
import { CollectionCarousel } from 'https://unpkg.com/@tacman1123/collection-slider/index.js';
new CollectionCarousel({
root: document.querySelector('#thumbnails'),
image: document.querySelector('#main-image'),
slider: document.querySelector('collection-slider'),
slides: [
{ value: 1954, thumb: 'https://example.test/thumb-1.jpg', id: 'FI001' },
{ value: 1954, thumb: 'https://example.test/thumb-2.jpg', id: 'FI002' },
// ...
],
});
</script>That's the entire integration. No build tool, no bundler config, no framework adapter.
With npm
npm install @tacman1123/collection-sliderimport { CollectionSlider, CollectionCarousel } from '@tacman1123/collection-slider';Works identically inside a bundler, inside Symfony AssetMapper's importmap, or as a raw
<script type="module"> tag — the package has no build-time dependencies of its own.
Demo & examples
All of these are static files — no build, no server-side dependency (demo/ uses php -S only
because that's a one-liner for a local static server; any static file server works).
| | What it shows |
|---|---|
| demo/ | The full, realistic case: a year slider + synced photo carousel, driven by real per-year counts from a live photo archive (synthetic placeholder thumbnails, since the demo has no image backend of its own). |
| examples/minimal/ | CollectionSlider completely alone — no carousel, just the raw collection-slider-change event, to show the element has no dependency on the rest of the package. |
| examples/generic-data/ | Proof the package isn't photo-specific: the same slider/counts mechanism driving a synthetic rainfall-by-year reading instead of an image. |
cd demo && php -S 127.0.0.1:8080 # then open /index.html
cd examples/minimal && php -S 127.0.0.1:8081
cd examples/generic-data && php -S 127.0.0.1:8082<collection-slider> attributes
| Attribute | Meaning |
|---|---|
| min, max, value, step | Standard numeric range, same semantics as <input type="range"> |
| tick-count | How many ruler ticks to draw |
| counts | JSON-encoded { "value": count } map — renders as "value · count" in the pill labels. Can also be set as a JS property: sliderEl.counts = { 1954: 35 } |
Events
collection-slider-change (bubbles, composed) fires with detail: { value, min, max, percent }
on every whole-value change while dragging, not only on release — this is what lets a paired
carousel glide with the knob instead of jumping once at the end of a drag. A separate
collection-slider-input event fires alongside it during drag for consumers that want the
distinction.
CollectionCarousel API
const carousel = new CollectionCarousel({
root, // container element — its children are replaced with the rendered strip
slides, // [{ value, thumb, id?, alt? }, ...], ordered by value
image, // optional <img> to update with the active slide
indexLabel, // optional element to receive "N / total" text
slider, // optional <collection-slider> to sync with (listens for collection-slider-change)
gap, // optional CSS gap between thumbnails, default '0.5rem'
thumbSize, // optional thumbnail width, default '72px'
});
carousel.show(index); // jump to a slide by index
carousel.next();
carousel.previous();
carousel.indexForValue(1954); // nearest slide index for a given slider valueFramework notes
Custom elements work natively in React, Vue, Svelte, and Angular — no wrapper component is
required to render <collection-slider> itself. Two things worth knowing:
countsas a prop: most frameworks pass unrecognized lowercase props/attrs straight through as HTML attributes, so<collection-slider counts={JSON.stringify(data)}>works the same way the plain-HTML attribute does. If your framework's custom-element interop instead tries to set it as a JS property with an object/Map directly, that also works —countshas both an attribute and a property path (see above).- Events:
collection-slider-changeis a normalCustomEvent, soaddEventListener(via a ref/onMount-style hook) is the reliable cross-framework way to listen — JSX-styleonCollectionSliderChange-type prop listeners are not standardized for custom events across frameworks the way they are for built-in DOM events.
Origin
Built for Museado/OpenFoto's photo-archive timeline (a Fortepan.hu-style year ruler driving a fortepan.us-style live thumbnail strip), then extracted here so it isn't tied to that project's backend (folio-bundle/Symfony) — same "no local build step for consuming apps" principle as TimelineJS's modern runtime.
