Timeline
Five dated events in order, each with a marker, a date, a title and a line, joined by a hairline.
Use for dated events in chronological order. Choose the Stepper component for progress through a task rather than adapting this history layout.
Build with the LoamUI skill
Already added the LoamUI skill? Copy the prompt below. Your agent will check your project and help complete any missing setup before building.
Use the LoamUI skill to build the “Timeline” recipe for my application.
Add your content or describe what you want to change. New to the skill? Add it to your project.
Three allotments and a kitchen table
Five growers on the Ludlow allotments pool the seed they have saved and post packets to friends who ask.
The first catalogue
Forty varieties in a photocopied booklet, sold from a trestle table at the winter market.
Registered as a co-operative
Hedgerow becomes a community benefit society: one member, one vote, and the surplus goes back into growing.
The nursery opens at Bromfield
Two acres, a polytunnel and a drying barn, with trial beds any member can walk on open days.
A thousand members
The thousandth member joins the week the catalogue passes four hundred varieties.
import "./recipe.css"; export default function Recipe() { return ( <div className="timeline"> <ol role="list"> <li> <time dateTime="2014-04">April 2014</time> <h3>Three allotments and a kitchen table</h3> <p> Five growers on the Ludlow allotments pool the seed they have saved and post packets to friends who ask. </p> </li> <li> <time dateTime="2016-01">January 2016</time> <h3>The first catalogue</h3> <p> Forty varieties in a photocopied booklet, sold from a trestle table at the winter market. </p> </li> <li> <time dateTime="2019-03">March 2019</time> <h3>Registered as a co-operative</h3> <p> Hedgerow becomes a community benefit society: one member, one vote, and the surplus goes back into growing. </p> </li> <li> <time dateTime="2022-05">May 2022</time> <h3>The nursery opens at Bromfield</h3> <p> Two acres, a polytunnel and a drying barn, with trial beds any member can walk on open days. </p> </li> <li> <time dateTime="2025-09">September 2025</time> <h3>A thousand members</h3> <p>The thousandth member joins the week the catalogue passes four hundred varieties.</p> </li> </ol> </div> );}
@scope (.timeline) to ([class*="loam-"]) { @layer loamui.components { :scope { container-type: inline-size; } ol { --_dot: 0.875rem; --_gap: var(--loam-space-s); display: block grid; font-size: var(--loam-text-md); gap: var(--_gap); grid-template-columns: minmax(0, 1fr); list-style: none; margin-block: 0; overflow-wrap: anywhere; padding: 0; } li { display: block grid; gap: var(--loam-space-3xs) var(--loam-space-xs); grid-template-areas: "dot date" "dot title" "dot description"; grid-template-columns: var(--_dot) minmax(0, 1fr); margin-block: 0; &::before { background: var(--loam-color-primary-strong); block-size: var(--_dot); border-radius: var(--loam-radius-full); box-shadow: 0 0 0 3px var(--loam-color-bg); content: ""; font-size: var(--loam-text-sm); grid-area: dot; inline-size: var(--_dot); margin-block-start: calc((1lh - var(--_dot)) / 2); z-index: 1; } &:not(:last-child)::after { border-inline-start: 1px solid var(--loam-color-line-strong); content: ""; grid-area: dot; justify-self: center; margin-block: var(--_dot) calc(-1 * var(--_gap)); } } time { color: var(--loam-color-fg-muted); font-size: var(--loam-text-sm); font-variant-numeric: lining-nums tabular-nums; grid-area: date; } h3 { grid-area: title; margin-block: 0; } p { color: var(--loam-color-fg-muted); grid-area: description; margin-block: 0; max-inline-size: var(--loam-measure); text-wrap: pretty; } @media (forced-colors: active) { li { &::before { border: 1px solid CanvasText; } &::after { border-color: CanvasText; } } } }}
Use this recipe
Copy Recipe.tsx and recipe.css side by side into a React 19 project. Install @loamui/core and load the core stylesheet at your application root, as shown in the installation guide. The component imports its own stylesheet.
Replace the fictional history with chronological events and valid machine-readable dates. Select heading levels to fit the surrounding section. This presents a static history; use Stepper for progress through an interactive task.
Uses
No components: the element styles and the tokens carry this one on their own.
Design decisions
How this recipe answers the two pillars, and how it composes the primitives. These notes explain the design. The included tests cover structure and selected interactions; check contrast, keyboard behaviour and assistive technology support in your application.
- Modern
- An ol carries the order and a time element carries each date with its machine-readable value, while the dots and the connecting line are pseudo-elements, so nothing decorative reaches the accessibility tree. Layered scoped CSS measures the list through its outer wrapper, so each event and its connector resolve the same spacing tokens; named grid areas position the content, lh centres the decorative dot on the date line, and a negative margin joins the gaps.
- Accessible
- The list keeps role=list so its count survives list-style: none, and in forced colours the dot keeps an outline and the connector its ink where the fills would vanish.
- Composition
- Element styles alone: an ordered list, headings, paragraphs and time, so no component is imported and no Stepper is bent into a history.