Timeline
Data Display

Timeline

Ordered events: an audit trail, a deploy history, the life of a ticket. A marker column with a run of line down it, and a row built from slots.

Component behavior

Timeline is for events that already happened, in the order they happened. Every row carries a time, and the rail shows the order.

ActivityFeed combines Timeline with actor, action, target, relative timestamp, and day-group headings.

Use cases
  • Deployment, audit, status, or job history.
  • Events displayed in chronological order.
  • Events with different amounts of detail, including payloads.
Alternatives

ActivityFeed: rows use actor/action/target format with relative timestamps.

Stepper: the view shows current progress through a task.

List: rows do not have chronological order.

LogViewer: the content is a high-volume log stream.

Props

TimelineProps props
PropTypeDefaultDescription
itemsTimelineEvent[]—The events, newest first. Omit and write TimelineItem children instead.
childrenReactNode—TimelineItem children, for the composed path. Ignored when items is given.
variant"rail" | "cards" | "minimal""rail"Rail displays markers and connectors. Cards adds event frames. Minimal hides connectors and marker halos.
density"compact" | "normal" | "comfortable""normal"Marker, type and row padding together.
timePlacement"inline" | "leading" | "none""inline"Timestamp placement: inline, in a leading column, or hidden.
timeWidthnumber | string64Width of the leading time column. A number is px.
markerSizenumber | string18 (16 / 22 at compact / comfortable)Marker diameter and marker-column width. Larger markers overflow the column while remaining centered.
connectorbooleantrue (false for minimal)The run of line down the rail.
toneToneProp"neutral"Default marker color for events without a tone.
emptyStateReactNode—Shown in place of the list when items is given and empty.
onItemClick(event: TimelineEvent, index: number) => void—Renders rows as buttons. Do not include links or other interactive children in button rows.
renderItem(event: TimelineEvent, state: TimelineItemState) => ReactNode—Custom content beside the marker. Retains the connector, row state, and click handling.
renderMarker(event: TimelineEvent, state: TimelineItemState) => ReactNode—Replaces the marker while retaining the row.

TimelineEvent

TimelineEvent props
PropTypeDefaultDescription
idstring—Stable key.
titleReactNode—The headline.
descriptionReactNode—Secondary content below the title.
timeReactNode—Timestamp content. Use Timestamp or RelativeTime to format a date.
metaReactNode—Monospace source text beside the title.
toneToneProp—Colors this row's marker and its halo, and the detail block's edge.
iconReactNode—Glyph inside the marker, in place of the dot. The marker becomes a tinted disc to hold it.
markerReactNode—Replaces the event marker.
detailReactNode—Framed detail content below the row.
actionsReactNode—Right-aligned controls on the title row.
groupReactNode—Section heading before this event. Consecutive events repeating it sit under one, and the line breaks between sections.
activeboolean—Applies active styling with a tinted background and emphasized marker.
dashedboolean—Draws the run of line below this event dashed: history that is incomplete, or something still to come.

TimelineItem

The composed row. It takes every TimelineEvent slot except id and group, and reads the enclosing timeline’s shape from context, so a hand-written row looks like a generated one.

TimelineItemProps props
PropTypeDefaultDescription
titleReactNode—The headline.
metaReactNode—Monospace source text beside the title.
timeReactNode—Timestamp content positioned according to the enclosing Timeline.
descriptionReactNode—Secondary content below the title.
childrenReactNode—The description slot under another name, for the composed path. description wins if both are given.
detailReactNode—Framed detail content below the row.
actionsReactNode—Right-aligned controls on the title row.
toneToneProp—Colors this row's marker and its halo, and the detail block's edge.
iconReactNode—Glyph inside the marker, in place of the dot.
markerReactNode—Replaces the event marker.
contentReactNode—Replaces the row's slots entirely, keeping the rail, the state and the click. What Timeline's renderItem arrives as.
activeboolean—Applies active styling with a tinted background and emphasized marker.
dashedboolean—Draws the run of line below this row dashed.
onClick(event: MouseEvent<HTMLElement>) => void—Makes the row a button. Lands on the row, not the <li>.

Custom properties

Everything the component measures with is a custom property on the root, so density is tunable without restating a rule.

--m-timeline-* props
PropTypeDefaultDescription
--m-timeline-markerlength18px (16 / 22 at compact / comfortable)Marker diameter and marker-column width. Also sets connector alignment.
--m-timeline-dotlength8pxThe dot inside the marker, when the event has no icon.
--m-timeline-linelength1pxConnector thickness.
--m-timeline-gaplengthvar(--m-space-2)Between the rail and the row. It is the row's inline padding, so the hover fill grows with it.
--m-timeline-padlengthvar(--m-space-1_5)Row padding-block.
--m-timeline-fontlengthvar(--m-font-size-md)Title size. Meta, time and detail keep their own fixed steps.
--m-timeline-time-widthlength64pxLeading timestamp column width. Set through timeWidth.
ImportTSX
import { Timeline, TimelineItem } from "@solarius/onset";
import type {
  TimelineEvent,
  TimelineItemState,
  TimelineProps,
} from "@solarius/onset";

Data and composition

Pass items to generate rows or provide TimelineItem children directly. Both forms render the same row component.

items vs children

Variants

variant defaults to "rail". "cards" adds a frame around each event. "minimal" omits the connector and marker halo.

The three variants

Density

density retunes the marker, the type and the row padding together. compact suits side panels; comfortable suits pages that are mostly timeline.

Density

Timestamp placement

timePlacement="inline" displays timestamps at the end of the title row. "leading" adds a timestamp column before the marker. "none" hides timestamps.

timePlacement

The row's slots

Timeline slots are optional. title is the heading; meta is secondary source text; description is body text; detail contains framed content; and actions contains controls. icon renders in a tinted marker and marker replaces the marker.

Slots

Event groups

Consecutive events with the same group share a heading. Connectors break between groups. Set dashed on an event to use a dashed connector below it.

Grouped

Selection and clicking

onItemClick renders event rows as buttons. Do not place links or other interactive elements inside button rows. active applies selected styling.

Click a row

Empty

emptyState renders when an explicitly supplied items array is empty. It does not apply to the children composition form.

Nothing has happened yet.
Empty