Timeline
An activity feed or an order's history: events in order, each on a rail with a dot or an icon, joined by the line that makes them read as one sequence rather than a list of unrelated rows.
Walkthrough
1. Basic
An order's history. Times are dates, written the way a person says them, with the exact moment in the tooltip; pending is the step that has not happened yet — its dot pulses and the line into it is dashed.
<script lang="ts"> import { Timeline, TimelineItem } from 'omaris'; const now = Date.now(); const MINUTE = 60_000; const HOUR = 60 * MINUTE;</script><Timeline label="Order #4021" class="w-96 max-w-full"> <TimelineItem title="Order placed" time={now - 26 * HOUR} tone="neutral" /> <TimelineItem title="Payment confirmed" description="Visa ending 4242" time={now - 26 * HOUR + 2 * MINUTE} tone="neutral" /> <TimelineItem title="Shipped from Erbil" description="Aramex AX-99120-IQ" time={now - 5 * HOUR} /> <TimelineItem title="Out for delivery" time={now - 14 * MINUTE} pending /></Timeline> 2. Grouped
A feed grouped by day is one Timeline per group, each with a heading, which also names its list for a screen reader. compact is the dense variant for a feed rather than a history.
Today
Yesterday
<script lang="ts"> import { Timeline, TimelineItem } from 'omaris'; const now = Date.now(); const MINUTE = 60_000; const HOUR = 60 * MINUTE; const GROUPS = [ { heading: 'Today', events: [ { title: 'Ada merged #1042', at: now - 25 * MINUTE, tone: 'primary' }, { title: 'Grace commented on #1040', at: now - 2 * HOUR, tone: 'neutral' } ] }, { heading: 'Yesterday', events: [ { title: 'Build failed on main', at: now - 30 * HOUR, tone: 'destructive' }, { title: 'Release 0.9.2 published', at: now - 33 * HOUR, tone: 'success' } ] } ] as const;</script><div class="flex w-96 max-w-full flex-col gap-6"> {#each GROUPS as group (group.heading)} <Timeline heading={group.heading} variant="compact"> {#each group.events as event (event.title)} <TimelineItem title={event.title} time={event.at} tone={event.tone} /> {/each} </Timeline> {/each}</div> 3. Icons and content
An icon puts the event in a tonal circle instead of a dot; children carry whatever the event needs underneath — a comment, a set of labels.
<script lang="ts"> import { Avatar, Chip, Text, Timeline, TimelineItem } from 'omaris'; const now = Date.now(); const MINUTE = 60_000; const HOUR = 60 * MINUTE;</script><Timeline label="Activity on #1042" class="w-[28rem] max-w-full"> <TimelineItem title="Ada Lovelace commented" time={now - 40 * MINUTE}> {#snippet icon()}<Avatar size="xs" name="Ada Lovelace" colorize />{/snippet} <Text variant="body-sm" class="rounded-shape-md bg-surface-container-low p-3 text-surface-variant-foreground" > The inner loop is twice as fast now. Can someone check the edge cases around zero? </Text> </TimelineItem> <TimelineItem title="Labels added" time={now - 3 * HOUR} tone="neutral"> {#snippet icon()} ... {/snippet} <div class="flex flex-wrap gap-2"> <Chip size="sm" variant="tonal" tone="tertiary">performance</Chip> <Chip size="sm" variant="tonal">engine</Chip> </div> </TimelineItem> <TimelineItem title="Opened" description="by Ada Lovelace" time={now - 26 * HOUR} tone="success"> {#snippet icon()} ... {/snippet} </TimelineItem></Timeline> 4. Overridden
relative={false} writes dates in dateFormat instead of counting; a time that is not a date is shown as given. classes reaches every part — here a primary line and square markers — and the caller's own attributes stay.
<script lang="ts"> import { Timeline, TimelineItem } from 'omaris'; const now = Date.now(); const DAY = 24 * 60 * 60_000; const marker = { dot: 'rounded-xs', line: 'border-primary/40' };</script><Timeline label="Audit log" relative={false} dateFormat={{ day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }} class="w-80 max-w-full" data-log="audit"> <TimelineItem title="API key rotated" time={now - DAY} classes={marker} /> <TimelineItem title="Admin added" description="grace@example.com" time={now - 9 * DAY} classes={marker} /> <TimelineItem title="Next review" time="Every quarter" tone="neutral" pending classes={marker} /></Timeline>