Timeline
Ordered milestones on a dashed spine, a dated agenda of sessions, or a date-block schedule.
import {
Timeline,
TimelineEntry,
TimelineList,
TimelineText,
TimelineTitle,
} from '@fairgarden-private/design/components/Timeline'
The spine is always dashed: dashes mean path. Markers are semantic and decorative at once, so every state they show is also in words: a circle starts, an X marks a waypoint (past or planned, told apart by the date key), a triangle ends, and the solid dot means "now", defined by its dated label or a TimelineCaption. Entries never alternate sides. Use Index Rows for unordered or unrelated events.
Trail and date block
Trail and date block
trail is the default. The first entry draws the origin, the last the terminal, and the others waypoints; stage="current" draws the "now" dot and sets aria-current="step". ongoing keeps the last entry a waypoint and puts the terminal past it. Pass marker to override a shape. Dates sit above titles below 768 px of container, in a key column left of the spine from 768, and at 3 / gutter / 7 from 1024. date-block sets a TimelineDateStack (month, day, weekday) in a fixed key column with no spine. A TimelineTitleLink links a whole entry.
The first 40 acres
Neighbors pool their savings to buy the ravine.The meadow comes back
Controlled burns return the prairie grasses.Headwaters campaign
Raising funds to protect the upper creek.- 2028 · Planned
Trail to the ridge
● marks today, 22 Sep 2026.
Night walk
North kiosk, 7 p.m.Seed swap
Barn, 10 a.m.
import {
Timeline,
TimelineCaption,
TimelineDateStack,
TimelineEntry,
TimelineList,
TimelineText,
TimelineTitle,
TimelineTitleLink,
} from '@fairgarden-private/design/components/Timeline'
import styles from './trail.module.css'
/** A trail timeline (origin, waypoints, "now", terminal past the end) and a date-block schedule. */
export function TimelineTrail() {
return (
<div className={styles.stack}>
<Timeline ongoing>
<TimelineList>
<TimelineEntry stage="past" date={<time dateTime="1987">1987</time>}>
<TimelineTitle>The first 40 acres</TimelineTitle>
<TimelineText>Neighbors pool their savings to buy the ravine.</TimelineText>
</TimelineEntry>
<TimelineEntry stage="past" date={<time dateTime="2004">2004</time>}>
<TimelineTitle>
<TimelineTitleLink href="#trail">The meadow comes back</TimelineTitleLink>
</TimelineTitle>
<TimelineText>Controlled burns return the prairie grasses.</TimelineText>
</TimelineEntry>
<TimelineEntry stage="current" date={<time dateTime="2026-09-22">Today, 22 Sep 2026</time>}>
<TimelineTitle>Headwaters campaign</TimelineTitle>
<TimelineText>Raising funds to protect the upper creek.</TimelineText>
</TimelineEntry>
<TimelineEntry stage="planned" date="2028 · Planned">
<TimelineTitle>Trail to the ridge</TimelineTitle>
</TimelineEntry>
</TimelineList>
<TimelineCaption>● marks today, 22 Sep 2026.</TimelineCaption>
</Timeline>
<Timeline kind="date-block">
<TimelineList>
<TimelineEntry
date={<TimelineDateStack dateTime="2026-10-03" month="Oct" day="3" weekday="Sat" />}
>
<TimelineTitle>Night walk</TimelineTitle>
<TimelineText>North kiosk, 7 p.m.</TimelineText>
</TimelineEntry>
<TimelineEntry
date={<TimelineDateStack dateTime="2026-10-11" month="Oct" day="11" weekday="Sun" />}
>
<TimelineTitle>Seed swap</TimelineTitle>
<TimelineText>Barn, 10 a.m.</TimelineText>
</TimelineEntry>
</TimelineList>
</Timeline>
</div>
)
}
Agenda
Agenda
agenda groups sessions under TimelineDays: a date head in the heading ink, a scope caption that states the time zone once, then sessions led by the » marker in the accent. TimelineSessionTitle joins its meta with the serif's pipe and a no-break space, so a pipe never starts a line. Say "Happening now" or "Past" in TimelineMeta.
Saturday, 3 October
All times are Eastern.
Warblers of the ravine | Walk | 9–11 a.m.
A slow loop with the bird count leaders.Why meadows burn | Talk | 1–2 p.m.
Our stewardship director on fire as a tool.
import {
Timeline,
TimelineDateHead,
TimelineDay,
TimelineDescription,
TimelineList,
TimelineMeta,
TimelineScope,
TimelineSession,
TimelineSessionTitle,
} from '@fairgarden-private/design/components/Timeline'
/** Date heads in the heading ink, one scope caption, sessions led by the » marker. */
export function TimelineAgenda() {
return (
<Timeline kind="agenda">
<TimelineDay>
<TimelineDateHead>Saturday, 3 October</TimelineDateHead>
<TimelineScope>All times are Eastern.</TimelineScope>
<TimelineList>
<TimelineSession>
<TimelineSessionTitle meta={['Walk', '9–11 a.m.']}>Warblers of the ravine</TimelineSessionTitle>
<TimelineMeta>Happening now</TimelineMeta>
<TimelineDescription>A slow loop with the bird count leaders.</TimelineDescription>
</TimelineSession>
<TimelineSession>
<TimelineSessionTitle meta={['Talk', '1–2 p.m.']}>Why meadows burn</TimelineSessionTitle>
<TimelineDescription>Our stewardship director on fire as a tool.</TimelineDescription>
</TimelineSession>
</TimelineList>
</TimelineDay>
</Timeline>
)
}
Grounds and print
Light grounds are the default home; on deep grounds the spine takes the ground's accent. On saturated grounds keep to six entries, all in the one ink. In print the spine is 0.75 pt with 3 / 2.5 pt dashes, every marker is kept, entries never split, and "Today" should read "As of".
API Reference
Timeline and TimelineList
The timeline module: a TimelineList of TimelineEntrys (trail and
date-block), or TimelineDays holding a TimelineDateHead, a
TimelineScope and a TimelineList of TimelineSessions (agenda). A
TimelineCaption defines the current marker. Entries never alternate
sides; the spine is always dashed [D174].
| Prop | Type | Description |
|---|---|---|
kind | |
|
ongoing | | The timeline continues: the last entry keeps a waypoint and the
terminal marker sits past it. Default |
primary | | Primary Radix scale: markers, date keys, titles and text. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the spine, the agenda’s » markers
( |
The ordered entries (or an agenda day’s sessions). On an ongoing trail it closes with the terminal marker past the last entry.
TimelineEntry
One milestone: its date key, the spine with its marker, and the body
(TimelineTitle, TimelineText). Entries never split across pages.
| Prop | Type | Description |
|---|---|---|
date | | The date key: a |
marker | | Overrides the marker. By default the first entry draws the origin circle, the last the terminal triangle (unless the timeline is ongoing), the rest waypoint X’s, and the current entry the “now” dot. |
stage | |
|
TimelineTitle, TimelineTitleLink, TimelineText and TimelineCaption
The entry title: type-itemhead in --primary12, within the reading measure. Renders <h3>.
A linked entry’s one link, inside TimelineTitle: a §9.3 title Link
whose hit area stretches over the entry; the entry draws the ring.
| Prop | Type | Description |
|---|---|---|
external | | Adds the arrow-open mark and “(external site)” for assistive technology.
Default |
index | | Adds the screen-only visited ✓ used in long indexes, such as reference
and archive lists. Default |
list | | With |
muted | | Rests in |
primary | | Primary Radix scale: the link text and focus ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the accent underline. Never defaulted; omitted, it inherits the scope. |
className | | Extra class names, added after the module’s own. |
The entry text: type-body-ui in --primary12. Put long entries in a Collapsible.
The legend line that defines the current marker, e.g. “● Today, 22 Sep
2026″ (§8.11): type-caption in --primary12. In print, write it as
“As of 22 Sep 2026″.
TimelineDateStack
The date-block key (Sofar Sounds): MONTH / day / WEEKDAY, stacked. Pass dateTime.
| Prop | Type | Description |
|---|---|---|
day | | The day of the month: a large data numeral. |
month | | The month, e.g. “Jul”: |
weekday | | The weekday, e.g. “Sat”: |
Agenda parts
One agenda day: TimelineDateHead, TimelineScope, then a TimelineList of sessions.
The agenda date head: type-itemhead in --role-heading (a group head). Renders <h3>.
The scope caption, “All times are Eastern.": the time zone, stated once.
One agenda session, led by the » block marker in --role-accent:
TimelineSessionTitle, an optional TimelineMeta (“Happening now”,
“Past”) and a TimelineDescription.
The session title, type-itemhead in --primary12, with its meta pipe-joined. Renders <h4>.
| Prop | Type | Description |
|---|---|---|
meta | | Fields joined into the title with the serif’s own pipe: “Title | Format | Time”. A no-break space precedes each pipe, so a pipe never starts a line; leave out empty fields. |
A session’s meta line: type-caption in --primary12 (“Happening now”, “Past”).
A session’s description: type-body-ui in --primary12.
Additional types
TimelineCaptionProps
Props for TimelineCaption: paragraph props and render.
type TimelineCaptionProps = useRender.ComponentProps<'p'>TimelineDateHeadProps
Props for TimelineDateHead: heading props and render (default <h3>).
type TimelineDateHeadProps = useRender.ComponentProps<'h3'>TimelineDateStackProps
Props for TimelineDateStack: time props, render and the three lines.
type TimelineDateStackProps = {
/** The month, e.g. "Jul": `type-label` caps. */
month: React.ReactNode;
/** The day of the month: a large data numeral. */
day: React.ReactNode;
/** The weekday, e.g. "Sat": `type-label` caps. */
weekday?: React.ReactNode;
}TimelineDayProps
Props for TimelineDay: section props and render.
type TimelineDayProps = useRender.ComponentProps<'section'>TimelineDescriptionProps
Props for TimelineDescription: div props and render.
type TimelineDescriptionProps = useRender.ComponentProps<'div'>timelineEntry
Entry state classes (unmanaged element): the stage of a milestone.
type timelineEntry = timelineEntryTimelineEntryProps
Props for TimelineEntry: list-item props, render, the stage, the date key and a marker override.
type TimelineEntryProps = React.ClassAttributes<HTMLLIElement> &
React.LiHTMLAttributes<HTMLLIElement> &
__type & { stage?: TimelineStage; date?: React.ReactNode; marker?: TimelineMarker }TimelineKind
The three timeline builds (§12.14).
type TimelineKind = 'trail' | 'agenda' | 'date-block'TimelineListProps
Props for TimelineList: ol props and render.
type TimelineListProps = useRender.ComponentProps<'ol'>TimelineMarker
The §4.7 marker set drawn on the spine.
type TimelineMarker = 'origin' | 'waypoint' | 'terminal' | 'current'TimelineMetaProps
Props for TimelineMeta: paragraph props and render.
type TimelineMetaProps = useRender.ComponentProps<'p'>TimelineProps
Props for Timeline: section props, render, the kind, ongoing and the color axes.
type TimelineProps = React.ClassAttributes<HTMLElement> &
React.HTMLAttributes<HTMLElement> &
__type & {
kind?: TimelineKind;
ongoing?: boolean;
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
}TimelineScopeProps
Props for TimelineScope: paragraph props and render.
type TimelineScopeProps = useRender.ComponentProps<'p'>TimelineSessionProps
Props for TimelineSession: list-item props and render.
type TimelineSessionProps = useRender.ComponentProps<'li'>TimelineSessionTitleProps
Props for TimelineSessionTitle: heading props, render and the pipe-joined meta.
type TimelineSessionTitleProps = React.ClassAttributes<HTMLHeadingElement> &
React.HTMLAttributes<HTMLHeadingElement> &
__type & { meta?: React.ReactNode[] }TimelineStage
A milestone’s stage: past and planned keep the waypoint X (told apart by words); current is “now”.
type TimelineStage = 'past' | 'current' | 'planned'TimelineTextProps
Props for TimelineText: div props and render.
type TimelineTextProps = useRender.ComponentProps<'div'>TimelineTitleLinkProps
Props for TimelineTitleLink: Link props except kind, which is always title.
type TimelineTitleLinkProps = {
/** Extra class names, added after the module's own. */
className?: string;
/**
* Primary Radix scale: the link text and focus ring. Never defaulted;
* omitted, it inherits the scope [D133].
*/
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
/**
* Secondary Radix scale: the accent underline. Never defaulted; omitted,
* it inherits the scope.
*/
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
/**
* With `kind="nav"`: a list link (nav-panel, footer, drawer and breadcrumb
* lists), whose hover is `--role-link-hover` color only, plus the
* `--ds-stroke-1-5` `--role-accent` underline where that ink is
* `--primary12`. Without it, `nav` is bare navigation text (bar and
* utility items, page numbers, toolbar links), whose hover is the
* `--border-size-2` `--role-accent` underline (§9.3) [D181]. Default
* `false`.
*/
list?: boolean | null;
/**
* Adds the screen-only visited ✓ used in long indexes, such as reference
* and archive lists. Default `false` [D174, D175].
*/
index?: boolean | null;
/**
* Adds the arrow-open mark and "(external site)" for assistive technology.
* Default `false`.
*/
external?: boolean | null;
/**
* Rests in `--role-muted` instead of `--primary12`, as a breadcrumb's
* ancestors. Hover takes `--role-link-hover` only (the underline is added
* where that ink is `--primary12`); with `kind="nav"` it replaces the bar
* item's bare-text underline (§9.3, §9.8) [D181]. Default `false`.
*/
muted?: boolean | null;
}TimelineTitleProps
Props for TimelineTitle: heading props and render (default <h3>).
type TimelineTitleProps = useRender.ComponentProps<'h3'>Specification: DESIGN-SYSTEM.md §12.14 (timeline and agenda), §8.11 (the timeline method) and §5.10.2 (module reflow).