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

PropTypeDefaultDescription
stagesTimelineStage[]Coloured segments of the bar.
eventsTimelineEvent[]Nodes with staggered labels.
minnumbermin of stage/event valuesAxis start value.
maxnumbermax of stage/event valuesAxis end value.
maxTiersnumber3Cap on stacked label rows for de-collision.
Other div props (className, aria-*, etc.).

TimelineStage

FieldTypeDefaultDescription
labelstringSegment label, rendered sentence-case beneath the bar.
fromnumberAxis value where the stage begins.
tonumberAxis value where the stage ends.
intentTimelineIntent"neutral"Colour role for the segment fill.

TimelineEvent

FieldTypeDefaultDescription
labelstringPrimary label above the node.
sublabelstringSecondary line (e.g. "age 45", "someday").
atnumber | nullAxis value; null pins the event to the far right, dashed and muted.
intentTimelineIntent"neutral"Colour role for the node and leader line.
tooltipReactNodelabel + sublabelTooltip 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.

PropTypeDefaultDescription
rowsTimelineRow[]One entry per stacked timeline.
minnumbermin across all rowsShared axis start.
maxnumbermax across all rowsShared axis end.
ticksTimelineAxisTick[] | nullauto year ticksShared bottom axis; null hides it.
maxTiersnumber3Cap on stacked label rows per timeline.
Other div props (className, aria-*, etc.).

TimelineRow

FieldTypeDefaultDescription
labelstringRow label (e.g. a person's name), shown above the bar.
stagesTimelineStage[]This row's stages.
eventsTimelineEvent[]This row's events.

TimelineAxisTick

FieldTypeDefaultDescription
valuenumberAxis value the tick sits at.
labelstring | numberthe valueTick caption.

On this page