Timeline
Accessible, unstyled timeline built on a native ordered list with progress states.
| Package | @vizejs/ui/timeline |
| Maturity | stable |
| Own the source | vize lib pull timeline |
| Requires | collection, context, id |
| Aliases | timeline, activity feed, history, event log, progress steps |
| Covers | HTML ordered list, HTML time element, MUI Timeline, Mantine Timeline |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Timeline, TimelineRoot, TimelineConnector, TimelineContent, TimelineIndicator, TimelineItem, TimelineTime } from "@vizejs/ui/timeline";
Or copy the source into your project with vize lib pull timeline (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Labelled release timeline where the root value marks the current milestone. -->
<script setup lang="ts">
import {
TimelineConnector,
TimelineContent,
TimelineIndicator,
TimelineItem,
TimelineRoot,
TimelineTime,
} from "@vizejs/ui/timeline";
const releases = [
{ value: "alpha", title: "Alpha", date: "2026-06-01", label: "June 1" },
{ value: "beta", title: "Beta", date: "2026-08-15", label: "August 15" },
{ value: "stable", title: "Stable", date: "2026-10-24", label: "October 24" },
] as const;
</script>
<template>
<TimelineRoot aria-label="Release history" value="beta">
<TimelineItem v-for="release in releases" :key="release.value" :value="release.value">
<TimelineIndicator />
<TimelineConnector />
<TimelineContent>
<strong>{{ release.title }}</strong>
<TimelineTime :datetime="release.date">{{ release.label }}</TimelineTime>
</TimelineContent>
</TimelineItem>
</TimelineRoot>
</template>
API
Timeline
Source: src/families/data/timeline/timeline-root.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string | null |
null |
Value of the current item. Earlier items become complete, later ones upcoming. |
orientation |
TimelineOrientation |
"vertical" |
Layout axis exposed to styles. |
reversed |
boolean |
false |
List items newest first with the native reversed ordered-list semantics. |
ariaLabel |
string |
undefined |
Accessible name for the list. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the list. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineSlotState |
TimelineItem children. Receives the current value, axis, and item count. |
Exposed
| Member | Type | Description |
|---|---|---|
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
value |
— | |
values |
— |
TimelineRoot
Source: src/families/data/timeline/timeline-root.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string | null |
null |
Value of the current item. Earlier items become complete, later ones upcoming. |
orientation |
TimelineOrientation |
"vertical" |
Layout axis exposed to styles. |
reversed |
boolean |
false |
List items newest first with the native reversed ordered-list semantics. |
ariaLabel |
string |
undefined |
Accessible name for the list. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the list. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineSlotState |
TimelineItem children. Receives the current value, axis, and item count. |
Exposed
| Member | Type | Description |
|---|---|---|
element |
HTMLOListElement | null |
Rendered ordered list. |
value |
string | null |
Current item value. |
values |
readonly string[] |
Registered item values in document order. |
TimelineConnector
Source: src/families/data/timeline/timeline-connector.vue
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineItemSlotState |
Optional decorative content. Receives the owning item's progress state. |
TimelineContent
Source: src/families/data/timeline/timeline-content.vue
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineItemSlotState |
Item body such as a title and description. Receives the owning item's progress state. |
TimelineIndicator
Source: src/families/data/timeline/timeline-indicator.vue
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineItemSlotState |
Optional decorative content. Receives the owning item's progress state. |
TimelineItem
Source: src/families/data/timeline/timeline-item.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string | null |
null |
Item value compared with the root value to derive progress. |
status |
TimelineItemStatus |
undefined |
Explicit progress status that overrides the derived one. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
TimelineItemSlotState |
Item content. Receives the index, progress status, and whether this is the last item. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
string | null |
Item value, or null for untracked items. |
index |
number |
Zero-based position in document order. |
status |
TimelineItemStatus | null |
Progress status: explicit, derived from the root value, or null. |
last |
boolean |
Whether this is the last item, which usually omits its connector. |
element |
HTMLLIElement | null |
Rendered list item. |
TimelineTime
Source: src/families/data/timeline/timeline-time.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
datetime (required) |
string | Date |
required |
Machine-readable date, time, or duration for the native <time> element. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ /** Machine-readable datetime rendered into the |
Human-readable, consumer-formatted time text. Receives the ISO datetime string. |
Behavior
Normative state x input -> outcome table for timeline-root.vue,
timeline-item.vue, timeline-indicator.vue, timeline-connector.vue,
timeline-content.vue, and timeline-time.vue (@vizejs/ui/timeline). Every
row is proven by the named test in timeline.test.ts or
timeline-ssr.test.ts; compile-only guarantees live in
timeline.types.test-d.ts.
A timeline is a native <ol> of <li> items, so assistive technology already
announces item count and position. The current item carries
aria-current="step"; indicators and connectors are aria-hidden decoration;
TimelineTime renders a native <time datetime>.
| ID | State | Input | Outcome | Evidence |
|---|---|---|---|---|
| L1 | untracked | render | labelled ol/li structure, hidden decorative parts, last-item marker, native <time> |
renders a labelled ordered list with decorative parts and native time |
| L2 | root value |
render, value change | items before the value are complete, the match is current, later ones upcoming |
derives complete, current, and upcoming states from the root value |
| L3 | explicit item status |
render | the explicit status wins over derived progress | explicit item status overrides derived progress |
| L4 | reversed, horizontal |
render | native reversed numbering and orientation data attributes |
reversed and horizontal timelines expose native and data semantics |
| L5 | conditional items, Date |
insert item, render time | inserted items join document order; Date values serialize to deterministic ISO strings |
items added later join document order and Date values serialize to ISO |
| L6 | missing provider | setup | item parts fail closed with the shared context diagnostic | compound parts require matching providers |
| L7 | SSR and hydration | isolated render/mount | progress is derived during the single server pass and hydrates without warnings | timeline-ssr.test.ts |
Items render before later siblings register, so during server rendering an
item seen before the current value is treated as complete; after mount a
value that matches no item clears every derived status.