Skip to content

Timeline

import { Timeline, TimelineItem } from '@delightstack/components';

The TimelineItem is re-exported from the Timeline module. Both Timeline and TimelineItem are backed by the same Svelte component — when used inside a Timeline context, it renders as an item; at the top level, it renders as the container.

  1. Step 1
    First step completed.
  2. Step 2
    Currently in progress.
  3. Step 3
View code
<Timeline>
<TimelineItem title="Step 1" date="Jan 10" status="complete">
First step completed.
</TimelineItem>
<TimelineItem title="Step 2" date="Jan 11" status="active">
Currently in progress.
</TimelineItem>
<TimelineItem title="Step 3" status="pending" />
</Timeline>
  1. Order Confirmed
    Your order has been confirmed.
  2. Shipped
    Package picked up by carrier.
  3. Out for Delivery
    Expected delivery today.
  4. Delivered
View code
<script>
import { Timeline, TimelineItem } from '@delightstack/components';
</script>
<Timeline>
<TimelineItem status="complete" date="Jan 10" title="Order Confirmed">
Your order has been confirmed.
</TimelineItem>
<TimelineItem status="complete" date="Jan 11" title="Shipped">
Package picked up by carrier.
</TimelineItem>
<TimelineItem status="active" date="Jan 12" title="Out for Delivery">
Expected delivery today.
</TimelineItem>
<TimelineItem status="pending" title="Delivered" />
</Timeline>
  1. Order Placed
  2. Processing
  3. Shipping
  4. Delivered
View code
<Timeline horizontal>
<TimelineItem status="complete" title="Order Placed" />
<TimelineItem status="complete" title="Processing" />
<TimelineItem status="active" title="Shipping" />
<TimelineItem status="pending" title="Delivered" />
</Timeline>

Events alternate between left and right in vertical mode.

  1. Event A
    Description A
  2. Event B
    Description B
  3. Event C
    Description C
View code
<Timeline alternate>
<TimelineItem date="Jan 1" title="Event A">Description A</TimelineItem>
<TimelineItem date="Feb 1" title="Event B">Description B</TimelineItem>
<TimelineItem date="Mar 1" title="Event C">Description C</TimelineItem>
</Timeline>

Load more events as the user scrolls near the end of the timeline.

  1. Project Kickoff
    Initial planning and team formation.
  2. Design Phase
    Wireframes and mockups created.
  3. Development Sprint 1
    Core features implemented.
View code
<Timeline onloadmore={loadMoreEvents} pending>
{#each events as event}
<TimelineItem
date={event.date}
title={event.title}
status={event.status}
>
{event.description}
</TimelineItem>
{/each}
</Timeline>

Give an item an onclick and/or href to make it clickable (mirroring <Button>). Interactive items get a pointer cursor, a hover tint, a ripple, and a press effect; items without either stay static.

  1. Order Confirmed
    Tap to view the confirmation.
  2. Shipped
    Tap to track the package.
  3. Out for Delivery
    Tap for live updates.
  4. Delivered

Click an event above.

View code
<Timeline>
<TimelineItem
status="complete"
date="Jan 10"
title="Order Confirmed"
onclick={() => (selected = 'Order Confirmed')}>
Tap to view the confirmation.
</TimelineItem>
<TimelineItem status="active" date="Jan 12" title="Out for Delivery" href="/orders/123" />
</Timeline>

Return a promise from onclick and the step’s marker drives its own loading feedback (just like <Button>): a spinner appears in the circle if the work outlasts ~100ms, stays visible long enough not to blink, then a brief success check confirms a resolve. Re-clicks are ignored while it’s in flight.

  1. Build started
    Compiled successfully.
  2. Tests passed
    All checks green.
  3. Deploy
    Click to deploy — the marker shows a spinner while it runs, then a check.
View code
<script>
async function deploy() {
await new Promise((resolve) => setTimeout(resolve, 1500));
}
</script>
<Timeline>
<TimelineItem status="complete" date="9:00 AM" title="Build started">
Compiled successfully.
</TimelineItem>
<TimelineItem status="complete" date="9:02 AM" title="Tests passed">
All checks green.
</TimelineItem>
<TimelineItem status="active" date="9:05 AM" title="Deploy" onclick={deploy}>
Click to deploy — the marker shows a spinner while it runs, then a check.
</TimelineItem>
</Timeline>
  1. Custom Color
    A red-themed event marker.
View code
<Timeline>
<TimelineItem title="Custom Color" color="var(--color-error)">
A red-themed event marker.
</TimelineItem>
</Timeline>
View code
<Timeline skeleton={loading} skeleton_count={3}></Timeline>
PropTypeDefaultDescription
horizontalbooleanfalseHorizontal layout instead of vertical
alternatebooleanfalseAlternate items left/right (vertical) or top/bottom (horizontal)
pendingbooleanfalseShow a pending/loading indicator at the end
densebooleanfalseCompact event spacing
comfortablebooleanfalseRelaxed event spacing
animatebooleantruePlay the entrance reveal + active pulse. Set false for a fully static timeline. (The reveal is also skipped automatically when content replaces a skeleton.)
skeletonbooleanfalseShow loading skeleton
skeleton_countnumber3Number of skeleton items
idstringautoElement ID
classstring''Additional CSS classes
childrenSnippet-TimelineItem children
EventDetailDescription
onloadmore() => void | Promise<void>Called when scrolling near the end for on-demand loading
PropTypeDefaultDescription
dateDate | string-Event timestamp
titlestring''Event title
iconComponent-Marker icon component
colorstring-Marker color override (CSS color value)
status'complete' | 'active' | 'pending'-Event status for marker styling
hrefstring-Makes the item a link (renders an <a>). Enables hover/ripple/press effects
onclick(event) => void | Promise<void>-Click handler. Makes the item interactive (hover/ripple/press effects). Return a promise to show a loading spinner in the marker, then a success check on resolve
target'_self' | '_blank' | '_parent' | '_top'-Link target (used with href)
childrenSnippet-Event body content

The Timeline exports a TimelineContext interface for internal context:

interface TimelineContext {
horizontal: boolean;
alternate: boolean;
dense: boolean;
comfortable: boolean;
animate: boolean;
reveal: boolean;
register: () => number;
}
  • Timeline renders as an ordered list (<ol>) with role="list" for semantic structure
  • Dates use <time> elements with datetime attributes
  • Status is communicated visually through marker styling (a checked node for complete, a glowing/pulsing node for active, a hollow ring for pending)
  • Scroll-reveal animations respect prefers-reduced-motion — items appear without animation when reduced motion is preferred
  • The load-more sentinel and skeleton items use aria-hidden="true"
  • Horizontal mode supports native touch/swipe scrolling with CSS snap points