Liking cljdoc? Tell your friends :D

x-scroll-timeline

A scroll-driven timeline component that visualizes chronological entries along a vertical track with animated markers and progress fill. Entries activate as they scroll past a configurable trigger line. Supports straight and curved (SVG serpentine) track shapes, alternating or single-side layouts.

Tag name

x-scroll-timeline

Attributes

AttributeTypeDefaultDescription
layout"alternating" | "left" | "right""alternating"Entry positioning mode. alternating places entries on alternating sides of the track; left positions the track on the left with entries to the right; right positions the track on the right with entries to the left.
track"straight" | "curved""straight"Track rendering mode. straight uses a CSS line; curved renders an SVG serpentine path.
thresholdnumber [0, 1]0.5Viewport fraction where the trigger line sits. An entry becomes active when it spans this line.
no-progressbooleanabsentWhen present, disables the progress fill on the track. Markers still activate.
disabledbooleanabsentFreezes all scroll behavior. No events fire, no entries activate.
labelstring""Accessible label applied as aria-label on the container.
marker"dot" | "ring" | "none""dot"Marker style. dot is a filled circle; ring is an outlined circle; none hides markers.
autoplaybooleanabsentWhen present, enables automatic scrolling at a configurable speed.
autoplay-speednumber [1, 1000]50Scroll speed in pixels per second when autoplay is enabled.
autoplay-loopbooleanabsentWhen present, scrolls back to the component top when the page bottom is reached.
autoplay-indicatorbooleanabsentWhen present, shows a pause icon overlay when autoplay is paused by user interaction.

Properties (JavaScript)

PropertyTypeRead-onlyDescription
layoutstringnoReflects the layout attribute
trackstringnoReflects the track attribute
thresholdnumbernoReflects the threshold attribute
noProgressbooleannoReflects the no-progress attribute
disabledbooleannoReflects the disabled attribute
labelstringnoReflects the label attribute
markerstringnoReflects the marker attribute
activeIndexnumberyesIndex of the currently active entry, or -1 if none
progressnumberyesOverall scroll progress [0, 1]
autoplaybooleannoReflects the autoplay attribute
autoplaySpeednumbernoReflects the autoplay-speed attribute
autoplayLoopbooleannoReflects the autoplay-loop attribute
autoplayIndicatorbooleannoReflects the autoplay-indicator attribute
autoplayPausedbooleanyesWhether autoplay is currently paused by user interaction

Events

All events bubble and are composed (cross shadow DOM). None are cancelable.

EventDetailDescription
x-scroll-timeline-entry-change{ index, id, previousIndex, previousId }Fires when the active entry changes
x-scroll-timeline-entry-enter{ index, id, progress }Fires when an entry enters the trigger zone
x-scroll-timeline-entry-leave{ index, id, progress }Fires when an entry leaves the trigger zone
x-scroll-timeline-progress{ progress, activeIndex, activeId }Fires each frame while visible (throttled to >0.1% change)
x-scroll-timeline-enter{ progress }Component enters the viewport
x-scroll-timeline-leave{ progress }Component leaves the viewport
x-scroll-timeline-autoplay-pause{ progress, activeIndex, activeId }Autoplay paused by user interaction
x-scroll-timeline-autoplay-resume{ progress, activeIndex, activeId }Autoplay resumed after user interaction

Slots

SlotDescription
(default)Timeline entry children. Each child is a timeline entry.

Data attributes on children

Set by the author

AttributeDescription
data-dateDate or label text displayed alongside the entry's marker on the timeline track
idOptional identifier, included in event detail objects

Set by the component

AttributeDescription
data-activePresent on the currently active entry
data-side"left" or "right" — which side of the track the entry is on
data-index0-based index of the entry

Set on the host by the component

AttributeDescription
data-autoplay-pausedPresent when autoplay is paused by user interaction

CSS parts

PartDescription
containerOuter wrapper (has role="feed")
trackTrack column container
track-lineUnfilled straight track line
track-fillFilled portion of straight track (progress)
track-svgSVG element (curved mode)
track-pathUnfilled SVG path (curved mode)
track-fill-pathFilled SVG path (curved mode, progress)
entriesEntries wrapper containing the default slot
indicatorPause icon overlay (visible when autoplay is paused and autoplay-indicator is set)
liveHidden aria-live region

CSS custom properties

PropertyDefaultDescription
--x-scroll-timeline-track-colorrgba(0,0,0,0.12)Unfilled track color
--x-scroll-timeline-track-fill-color#3b82f6Filled/progress track color
--x-scroll-timeline-track-width3pxTrack line thickness
--x-scroll-timeline-marker-size14pxMarker diameter
--x-scroll-timeline-marker-colorrgba(0,0,0,0.15)Inactive marker fill
--x-scroll-timeline-marker-active-color#3b82f6Active marker fill
--x-scroll-timeline-marker-border-color#3b82f6Marker border color
--x-scroll-timeline-entry-gap2remVertical spacing between entries
--x-scroll-timeline-date-colorrgba(0,0,0,0.5)Date label text color
--x-scroll-timeline-date-font-size0.8125remDate label font size
--x-scroll-timeline-transition-duration300msActivation transition duration
--x-scroll-timeline-curve-amplitude60SVG curve horizontal amplitude (pixels, curved mode)
--x-scroll-timeline-disabled-opacity0.55Opacity when disabled

Accessibility

  • The container has role="feed" with an aria-label from the label attribute.
  • A hidden aria-live="polite" region announces "Entry N active" on entry changes.
  • Respects @media (prefers-reduced-motion: reduce) by disabling all transitions and scroll tracking.
  • Active entries receive data-active which can be targeted for screen reader announcements.
  • When autoplay is active, the element receives tabindex="0" for keyboard control. Holding Space pauses autoplay; releasing Space resumes it. Mouse/touch interactions also pause while held and resume on release.
  • Autoplay will not start if the user prefers reduced motion (prefers-reduced-motion: reduce).

Usage

Basic timeline

<x-scroll-timeline label="Project history">
  <div data-date="Jan 2024">
    <h3>Project started</h3>
    <p>Initial planning and architecture design.</p>
  </div>
  <div data-date="Mar 2024">
    <h3>Alpha release</h3>
    <p>First internal release for testing.</p>
  </div>
  <div data-date="Jun 2024">
    <h3>Public launch</h3>
    <p>Official 1.0 release.</p>
  </div>
</x-scroll-timeline>

Curved track with ring markers

<x-scroll-timeline track="curved" marker="ring" layout="alternating">
  <div data-date="2023">Content</div>
  <div data-date="2024">Content</div>
  <div data-date="2025">Content</div>
</x-scroll-timeline>

Left-aligned timeline

<x-scroll-timeline layout="left">
  <div data-date="Step 1">Content</div>
  <div data-date="Step 2">Content</div>
</x-scroll-timeline>

Autoplay with loop

<x-scroll-timeline autoplay autoplay-speed="80" autoplay-loop autoplay-indicator
                   label="Auto-scrolling timeline">
  <div data-date="2023">Content</div>
  <div data-date="2024">Content</div>
  <div data-date="2025">Content</div>
</x-scroll-timeline>

Listening for events

const tl = document.querySelector('x-scroll-timeline');

tl.addEventListener('x-scroll-timeline-entry-change', e => {
  console.log('Active entry:', e.detail.index, e.detail.id);
});

tl.addEventListener('x-scroll-timeline-progress', e => {
  console.log('Progress:', e.detail.progress.toFixed(2));
});

Custom styling

x-scroll-timeline {
  --x-scroll-timeline-track-fill-color: #8b5cf6;
  --x-scroll-timeline-marker-active-color: #8b5cf6;
  --x-scroll-timeline-marker-size: 18px;
  --x-scroll-timeline-entry-gap: 3rem;
  --x-scroll-timeline-curve-amplitude: 80;
}

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close