Skip to content
v1.3.1
Fit

Timeline

A vertical activity feed. Each entry is a dot on a connecting rail with a title, optional timestamp, description, and arbitrary trailing content. Give a dot a tone for status colour and an icon for a marker glyph — without an icon it renders as a full-size dot in the tone colour, or set plain for a small compact dot. Display-only, so plain HTML needs no JavaScript.

bash
jlds add timeline

Usage

html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/timeline.css">

<ol class="jl-timeline">
  <li class="jl-timeline__item">
    <div class="jl-timeline__rail">
      <span class="jl-timeline__dot" data-tone="accent" aria-hidden="true">
        <svg viewBox="0 0 24 24" fill="none"><path d="M20 6 9 17l-5-5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
      </span>
      <span class="jl-timeline__line" aria-hidden="true"></span>
    </div>
    <div class="jl-timeline__body">
      <div class="jl-timeline__head">
        <span class="jl-timeline__title">Order placed</span>
        <span class="jl-timeline__time">2h ago</span>
      </div>
      <div class="jl-timeline__desc">We received your order and sent a confirmation email.</div>
    </div>
  </li>
  <!-- more .jl-timeline__item blocks; the last item's line is hidden automatically -->
</ol>
vue
<script setup lang="ts">
import { Timeline, TimelineItem } from "@/components/ui/timeline"
</script>

<template>
  <Timeline>
    <TimelineItem title="Order placed" time="2h ago" tone="accent"
      description="We received your order and sent a confirmation email." />
    <TimelineItem title="Payment confirmed" time="1h ago" tone="success"
      description="Your card was charged $48.00." />
    <TimelineItem title="Preparing shipment" time="Now"
      description="Your items are being packed at the warehouse." />
  </Timeline>
</template>
tsx
import { Timeline } from "@/components/ui/timeline"

<Timeline>
  <Timeline.Item title="Order placed" time="2h ago" tone="accent"
    description="We received your order and sent a confirmation email." />
  <Timeline.Item title="Payment confirmed" time="1h ago" tone="success"
    description="Your card was charged $48.00." />
  <Timeline.Item title="Preparing shipment" time="Now"
    description="Your items are being packed at the warehouse." />
</Timeline>

Both React and Vue also accept a data-driven items array instead of children — pass [{ title, time, description, tone }].

Small & plain

size="sm" tightens the rail; add plain for a compact dot-only feed.

html
<ol class="jl-timeline jl-timeline--sm">
  <li class="jl-timeline__item">
    <div class="jl-timeline__rail">
      <span class="jl-timeline__dot" data-tone="accent" data-plain="true" aria-hidden="true"></span>
      <span class="jl-timeline__line" aria-hidden="true"></span>
    </div>
    <div class="jl-timeline__body">
      <div class="jl-timeline__head">
        <span class="jl-timeline__title">Pushed 3 commits</span>
        <span class="jl-timeline__time">09:24</span>
      </div>
    </div>
  </li>
  <!-- … -->
</ol>
vue
<template>
  <Timeline size="sm">
    <TimelineItem title="Pushed 3 commits" time="09:24" tone="accent" plain />
    <TimelineItem title="Opened pull request #128" time="09:31" plain />
    <TimelineItem title="Merged to main" time="10:02" tone="success" plain />
  </Timeline>
</template>
tsx
<Timeline size="sm">
  <Timeline.Item title="Pushed 3 commits" time="09:24" tone="accent" plain />
  <Timeline.Item title="Opened pull request #128" time="09:31" plain />
  <Timeline.Item title="Merged to main" time="10:02" tone="success" plain />
</Timeline>

Props

React

Timeline extends React.HTMLAttributes<HTMLOListElement>.

PropTypeDefaultDescription
itemsTimelineItemData[]Data-driven entries (omit when using Timeline.Item children)
size"sm" | "md""md"Rail density

Timeline.Item props:

PropTypeDefaultDescription
titleReactNodeEntry headline
timeReactNodeRight-aligned timestamp
descriptionReactNodeSecondary text under the title
tone"accent" | "success" | "warning" | "danger" | "info" | "muted""muted"Dot colour
iconReactNodeMarker glyph; without one the dot is a full-size circle in the tone colour
plainbooleanfalseRender a small compact dot instead of a full-size marker

Vue

Timeline (size, items) + TimelineItem (title, time, description, tone, plain). Pass a marker via the icon slot and trailing content via the default slot.

CSS classes (HTML)

ClassPurpose
.jl-timeline + --smThe feed list and compact size
.jl-timeline__itemOne entry (last item's line is hidden)
.jl-timeline__rail / __dot / __lineThe marker column
.jl-timeline__dot[data-tone]Dot colour (accent, success, warning, danger, info, muted)
.jl-timeline__dot[data-plain="true"]Small compact dot (opt-in; default is a full-size dot)
.jl-timeline__body / __head / __title / __time / __desc / __extraThe content column