Skip to content
RU
Scale
Density
Theme
Accent

Data display

Timeline

A chronology: what happened and when. The dots are joined by a line, so the timeline reads as a sequence rather than as a list.

The component
Run finished
4 files changed
14:36
Indexing
terrain/
14:32
Markup
<div class="inst-timeline">
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="ok"></span>
    <div class="inst-timeline-body">
      Run finished
      <div class="inst-timeline-sub">4 files changed</div>
    </div>
    <span class="inst-timeline-time">14:36</span>
  </div>
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="running"></span>
    <div class="inst-timeline-body">
      Indexing
      <div class="inst-timeline-sub">terrain/</div>
    </div>
    <span class="inst-timeline-time">14:32</span>
  </div>
</div>

Contract

What Required Why
<ol> and <li> yes The order carries meaning here, and a screen reader has to announce "a list of N"
<time datetime> yes "14:36" with no date is ambiguous outside the context of a day
The tone is repeated in words in the description yes A dot by itself says nothing to somebody who does not tell tones apart
data-tone no Without the attribute the dot is neutral

The line is drawn by a pseudo-element and does not reach the speaking — it is decorative.

Accessibility

This is a list Wrap it in an <ol> and an event in an <li>: the order carries meaning here, and a screen reader has to announce "a list of N"
Time A <time datetime="…"> with a machine value. "14:36" with no date is ambiguous outside the context of a day
Not colour alone The tone of a dot is repeated in words in the description of the event. A dot by itself says nothing to somebody who does not tell tones apart
The line Drawn by a pseudo-element and does not reach the speaking — which is right, it is decorative
Reduced motion The pulse of a running dot slows down rather than going out

Variants

A dot takes the same data-tone as the whole library.

Example
An ordinary event
Happening now
Finished successfully
With remarks
A refusal
Markup
<div class="inst-timeline">
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot"></span>
    <div class="inst-timeline-body">An ordinary event</div>
  </div>
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="running"></span>
    <div class="inst-timeline-body">Happening now</div>
  </div>
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="ok"></span>
    <div class="inst-timeline-body">Finished successfully</div>
  </div>
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="warn"></span>
    <div class="inst-timeline-body">With remarks</div>
  </div>
  <div class="inst-timeline-item">
    <span class="inst-timeline-dot" data-tone="error"></span>
    <div class="inst-timeline-body">A refusal</div>
  </div>
</div>
Tone When
no attribute An ordinary event
data-tone="running" Happening now. The dot pulses
data-tone="ok" A successful finish
data-tone="warn" With remarks
data-tone="error" A refusal

API

Classes
NameWhat it does
class
inst-timelineThe container
inst-timeline-itemOne event
inst-timeline-dotThe dot on the line
inst-timeline-bodyThe description of the event
inst-timeline-subA detail under the description
inst-timeline-timeThe timestamp, pushed to the end
Attributes
NameValueWhat it does
attribute
data-tone—neutral running ok warn error
Tokens
NameValueWhere from
token
--size-gutter14pxbase +14: density · scale
--gap-inlinevar(--space-4)base +14: density · scale
--row-pad-yvar(--space-3)base +14: density · scale
--size-dot6pxbase +4: scale
--size-marker2pxbase +4: scale
--borderlight-dark(oklch(0 0 0 / 0.12), oklch(1 0 0 / 0.11))one across every cell
--text-sm0.875rembase +4: scale
--text-xs0.78125rembase +4: scale
--text-mutedlight-dark(var(--n-8), var(--n-6))one across every cell
--tone-markvar(--text-secondary)base +4:

Why the kit works this way — the constitution · Open source under MIT, github.com/keshon/instrument