Fylgja Timeline

A timeline lists events in order along a vertical line, each with a date, a title, and a short description. It is a plain <ol>, so the order is real for assistive tech, and every date is a <time> element with a machine readable datetime.

Preview

  1. Version 2.0 released

    A new token set, container query utilities, and a smaller base.

  2. Public beta

    The first builds go out to early adopters for feedback.

  3. Project kickoff

    The idea takes shape as a set of small, independent CSS packages.

<ol role="list" class="timeline">
	<li>
		<hgroup>
			<p><time datetime="2026-09-14">September 14, 2026</time></p>
			<h3 class="lead">Version 2.0 released</h3>
		</hgroup>
		<p>A new token set, container query utilities, and a smaller base.</p>
	</li>
	<li>
		<hgroup>
			<p><time datetime="2026-06-02">June 2, 2026</time></p>
			<h3 class="lead">Public beta</h3>
		</hgroup>
		<p>The first builds go out to early adopters for feedback.</p>
	</li>
	<li>
		<hgroup>
			<p><time datetime="2026-01-20">January 20, 2026</time></p>
			<h3 class="lead">Project kickoff</h3>
		</hgroup>
		<p>The idea takes shape as a set of small, independent CSS packages.</p>
	</li>
</ol>

<style>
	.timeline {
		--timeline-gap: 1.5rem;
		--timeline-line: color-mix(in oklab, var(--root-bg) 75%, var(--root-fg));
		--timeline-marker: var(--brand);
		--timeline-marker-size: 0.75rem;
		border-inline-start: 2px solid var(--timeline-line);
		margin-inline-start: calc(var(--timeline-marker-size) / 2);
		padding-inline-start: var(--timeline-gap);

		> li {
			position: relative;
		}

		> li::before {
			content: "";
			position: absolute;
			inset-block-start: calc(0.5lh - var(--timeline-marker-size) / 2);
			inset-inline-start: calc(-1 * (var(--timeline-gap) + 1px + var(--timeline-marker-size) / 2));
			inline-size: var(--timeline-marker-size);
			aspect-ratio: 1;
			border-radius: 50%;
			background: var(--timeline-marker);
			box-shadow: 0 0 0 3px var(--root-bg);
		}
	}
</style>

Usage

  • Put the events in an <ol role="list" class="timeline">, one <li> per event, newest or oldest first as the content needs.
  • Pair the date and title in an <hgroup>, with the date in a <p> and a <time datetime> inside it. The <hgroup> keeps them tight together, while the description below gets the usual paragraph spacing.
  • The small .timeline rule draws the line as a border on the list and each marker as a ::before on the item. Tune it with --timeline-gap, --timeline-line, --timeline-marker, and --timeline-marker-size.

Anatomy

Part Responsibility
<ol class="timeline"> The list of events, and the vertical line.
<li> One event, with its marker drawn in ::before.
<hgroup> Keeps the date and the event title together.
<time datetime> The date, readable by people and machines.

Accessibility

  • role="list" keeps the list semantics that Safari drops once list-style is removed.
  • The line and markers are decoration drawn in CSS, so assistive tech skips them. If a marker carries meaning, such as a finished or upcoming step, say so in the text too.
  • Use a heading level that fits the page outline around the timeline.

Related: Stepper, Accordion.

FAQ

Why an ordered list?

The events happen in a set order, and an ol tells assistive tech so. A screen reader announces how many events there are and where the reader is among them.

Why wrap the date in a time element?

The datetime attribute gives the date in a machine readable format, while the visible text can be written however suits the reader, such as June 2, 2026.

Can I color a single marker?

Yes. Set the --timeline-marker variable on that list item, for example to a success color for a finished step.

Does the line work in right to left languages?

Yes. The line and markers use logical properties (inline start), so they move to the right side on their own.