Timeline

A sequence of events laid along a rail.

Basic

Each event is a .timeline__item holding a .timeline__marker on the rail and a .timeline__body beside it. The rail line draws itself between markers and stops at the last one. It is pure layout with no JS; status rides an author-set data-state and intent rides a .timeline__marker--* modifier. An empty marker paints a dot on the rail. Use an <ol> for the root so the order carries to screen readers.

Icon and avatar markers

Drop an icon inside a marker for a system event or an avatar for a person. Every marker is the same size, so they line up however you mix them; bump --timeline-marker-size on the root to scale them together. Avatars and images sit on the rail directly, without the tinted ring an icon marker gets.

Status

Set data-state on an item to show where it sits in a process. A complete step fills its marker and keeps the rail solid, current rings the marker and dashes the rail leaving it, and pending mutes the marker and dashes the rest.

Time at the bottom

The body is a plain stack, so the time sits wherever you place it. Lead with the title and drop .timeline__time to the last line when it reads better as a caption. The marker aligns to the first line.

Marker colors

Add a .timeline__marker--* modifier to color a marker for a fixed meaning. Color is separate from status, so a marker can carry an intent color whether or not the item has a data-state. For a one-off color, set --timeline-marker-color on the item instead.

Alternate

Add .timeline--alternate to center the rail and place events on either side of it. It needs room, so on a narrow screen it folds back to the standard left rail. Status and marker content work the same way.

Customization

These variables retune .timeline without touching component CSS. Set them on the timeline, a parent scope, or :root. The marker color also reads on a single .timeline__item, which is how the intent modifiers and a one-off override work. For a neutral activity feed, set --timeline-marker-color to var(--color-muted-foreground) on the root.

Geometry

VariableUse
--timeline-marker-sizeMarker size; every marker is a circle of this size and one value scales them all
--timeline-dot-sizeDiameter of the dot shown when a marker is empty
--timeline-connector-widthThickness of the rail line
--timeline-connector-gapSpace between a marker and the line at both ends of each segment
--timeline-connector-styleRail line style; solid by default, the current and pending states switch it to dashed
--timeline-gutterSpace between the rail and the event body
--timeline-gapVertical space between events

Paint

VariableUse
--timeline-marker-colorMarker fill, dot, and tint; the intent modifiers set this and an item-level override wins for one row
--timeline-marker-color-emphasisGlyph colour inside a tinted marker; intents set it from --color-<intent>-emphasis for AA contrast
--timeline-marker-ringRing color around a current marker
--timeline-marker-ring-sizeStatic halo thickness on a current marker
--timeline-ping-durationHow long one ping of a current marker takes; dropped under reduced motion
--timeline-connector-colorRail line color