Timeline
A compressed, to-scale event timeline — coloured life stages along a value axis with staggered event markers and tooltips.
Now
age 42
House £100k
age 45
Stop working
age 50
Pension unlocks
age 57
State pension
age 67
Business sale?
someday
Working
Early retirement
Full retirement
<Timeline min={42} max={90} stages={[ { label: "Working", from: 42, to: 50, intent: "neutral" }, { label: "Early retirement", from: 50, to: 57, intent: "caution" }, { label: "Full retirement", from: 57, to: 90, intent: "warning" }, ]} events={[ { label: "Now", sublabel: "age 42", at: 42, intent: "neutral" }, { label: "House £100k", sublabel: "age 45", at: 45, intent: "caution" }, { label: "Stop working", sublabel: "age 50", at: 50, intent: "neutral" }, { label: "Pension unlocks", sublabel: "age 57", at: 57, intent: "warning" }, { label: "State pension", sublabel: "age 67", at: 67, intent: "constructive" }, { label: "Business sale?", sublabel: "someday", at: null }, ]}/>Usage
import { Timeline } from "@reva/ui";Timeline is data-driven: pass a stages array (the coloured segments of the bar) and an events array (the nodes with staggered labels). Positions are to-scale on a single numeric axis — event and stage boundaries share the same value space (ages here, but any number works). The axis runs from min to max; both default to the smallest and largest values across the stages and dated events.
Event labels are staggered into rows automatically so they never overlap, and each node carries a tooltip on hover and keyboard focus.
Examples
Undated events
Give an event at: null to mark it as undated ("someday"). It pins to the far right of the axis with a dashed, muted treatment, signalling that its timing is unknown.
The retirement example above uses this for Business sale? — the value is real to the plan, but the date isn't set.
Simple two-stage plan
Any pair of stages and a handful of events. Colour carries meaning through the intent axis, so a saving phase can read as info and a drawdown phase as constructive.
Start
age 30
Mortgage clear
age 52
Retire
age 60
Saving
Drawdown
<Timeline stages={[ { label: "Saving", from: 30, to: 60, intent: "info" }, { label: "Drawdown", from: 60, to: 85, intent: "constructive" }, ]} events={[ { label: "Start", sublabel: "age 30", at: 30, intent: "info" }, { label: "Mortgage clear", sublabel: "age 52", at: 52, intent: "info" }, { label: "Retire", sublabel: "age 60", at: 60, intent: "constructive" }, ]}/>Comparing people on one scale
The axis is just numbers, so it isn't tied to age. To stack several people and read them against each other, position events by calendar year (keeping the age in the sublabel) and let TimelineGroup share one scale across every row.
TimelineGroup computes a shared min / max across all rows so the bars line up, labels each row, and draws one shared axis of year ticks along the bottom. Here Anna (born 1984) and Ben (born 1988) sit on the same wall-clock years — the same instant is a different age for each.
Anna
Now
age 42
House £100k
age 45
Stop working
age 50
Pension unlocks
age 57
State pension
age 67
Business sale?
someday
Working
Early retirement
Full retirement
Ben
Now
age 38
Career change
age 44
Stop working
age 55
Pension unlocks
age 57
State pension
age 68
Working
Early retirement
Full retirement
2030
2040
2050
2060
2070
<TimelineGroup rows={[ { label: "Anna", stages: [ { label: "Working", from: 2026, to: 2034, intent: "neutral" }, { label: "Early retirement", from: 2034, to: 2041, intent: "caution" }, { label: "Full retirement", from: 2041, to: 2074, intent: "warning" }, ], events: [ { label: "Now", sublabel: "age 42", at: 2026, intent: "neutral" }, { label: "Stop working", sublabel: "age 50", at: 2034, intent: "neutral" }, { label: "State pension", sublabel: "age 67", at: 2051, intent: "constructive" }, { label: "Business sale?", sublabel: "someday", at: null }, ], }, { label: "Ben", stages: [ { label: "Working", from: 2026, to: 2043, intent: "neutral" }, { label: "Full retirement", from: 2043, to: 2078, intent: "warning" }, ], events: [ { label: "Now", sublabel: "age 38", at: 2026, intent: "neutral" }, { label: "Stop working", sublabel: "age 55", at: 2043, intent: "neutral" }, { label: "State pension", sublabel: "age 68", at: 2056, intent: "constructive" }, ], }, ]}/>Props
Timeline
| Prop | Type | Default | Description |
|---|---|---|---|
stages | TimelineStage[] | — | Coloured segments of the bar. |
events | TimelineEvent[] | — | Nodes with staggered labels. |
min | number | min of stage/event values | Axis start value. |
max | number | max of stage/event values | Axis end value. |
maxTiers | number | 3 | Cap on stacked label rows for de-collision. |
| … | — | — | Other div props (className, aria-*, etc.). |
TimelineStage
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Segment label, rendered sentence-case beneath the bar. |
from | number | — | Axis value where the stage begins. |
to | number | — | Axis value where the stage ends. |
intent | TimelineIntent | "neutral" | Colour role for the segment fill. |
TimelineEvent
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Primary label above the node. |
sublabel | string | — | Secondary line (e.g. "age 45", "someday"). |
at | number | null | — | Axis value; null pins the event to the far right, dashed and muted. |
intent | TimelineIntent | "neutral" | Colour role for the node and leader line. |
tooltip | ReactNode | label + sublabel | Tooltip content on hover / focus. |
TimelineIntent is the shared 8-intent vocabulary: primary · accent · neutral · destructive · constructive · warning · caution · info.
TimelineGroup
Stacks several timelines on one shared scale.
| Prop | Type | Default | Description |
|---|---|---|---|
rows | TimelineRow[] | — | One entry per stacked timeline. |
min | number | min across all rows | Shared axis start. |
max | number | max across all rows | Shared axis end. |
ticks | TimelineAxisTick[] | null | auto year ticks | Shared bottom axis; null hides it. |
maxTiers | number | 3 | Cap on stacked label rows per timeline. |
| … | — | — | Other div props (className, aria-*, etc.). |
TimelineRow
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Row label (e.g. a person's name), shown above the bar. |
stages | TimelineStage[] | — | This row's stages. |
events | TimelineEvent[] | — | This row's events. |
TimelineAxisTick
| Field | Type | Default | Description |
|---|---|---|---|
value | number | — | Axis value the tick sits at. |
label | string | number | the value | Tick caption. |