caliper uidocs

Depth timeline

Free

Time as distance. The current row is near and sharp, what comes later recedes along the road, and what has shipped slips behind you. Distance follows certainty too: far rows are labelled Planned or Exploring, and every date and status is written out.

Installs components/ui/depth-timeline.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add @caliper/depth-timeline
2 of 6 · Oct 16

When to use #

Use it for

  • Roadmaps and release plans where the near term is firm and the far term is not.
  • Showing how much of a plan is committed.

Skip it when

  • A history log; use the timeline.
  • Dates that must be compared side by side; use a table.

Decisions #

Why it is built this way, so you know what to keep when you change your copy.

Behaviour

Depth never carries a fact alone
Date, distance in words and status are always text. Depth only adds the feel of how far away something is.
Every row is in the reading order
It is an ordered list; far rows stay reachable by click and by screen reader, and the current row is aria-current.

Installation #

terminal
pnpm dlx shadcn@latest add @caliper/depth-timeline

Adds its 5 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { DepthTimeline } from "@/components/ui/depth-timeline"

export function DepthTimelineDemo() {
  return (
    <div className="w-full max-w-lg">
      <DepthTimeline
        label="Roadmap"
        defaultCurrent={1}
        items={[
          { id: "css", date: "Oct 02", away: "2 weeks ago", status: "Shipped", title: "Per-part stylesheets", description: "Dialog now installs about 12 KB of CSS instead of the whole sheet." },
          { id: "shadcn", date: "Oct 16", away: "today", status: "Shipped", title: "Listed in the shadcn directory", description: "shadcn add @caliper/<name> works with no registry config." },
          { id: "depth", date: "Oct 30", away: "in 2 weeks", status: "In progress", title: "Depth set: ten 3D parts", description: "Six Free, four Pro. Each has a flat twin." },
          { id: "tokens", date: "Nov 20", away: "in 5 weeks", status: "Planned", certainty: "planned", title: "Design token export", description: "JSON and CSS variables from the same source." },
          { id: "charts", date: "Dec 18", away: "in 9 weeks", status: "Planned", certainty: "planned", title: "Charts on live data", description: "Adapters for polling and streaming sources." },
          { id: "expo", date: "Q1", away: "later", status: "Exploring", certainty: "exploring", title: "Expo package for native", description: "Only if the docs show real demand." },
        ]}
      />
    </div>
  );
}

API reference #

DepthTimeline

component
PropTypeDefaultDescription
label *string—
items *readonly DepthTimelineItem[]—
currentnumber—Index of the current row. Controlled when set.
defaultCurrentnumber0
onCurrentChange((index: number) => void)—
statusDepthStatus"ready"
messagesDepthMessages—
onRetry(() => void)—
disabledboolean—
classNamestring—

Accessibility #

It exposes group semantics, with aria-current, aria-roledescription, aria-label and aria-live kept in step with state. Changes that matter are announced through a live region.

KeyBehaviour
→Moves to the next item or value.
↓Moves to the next item or value.
←Moves to the previous item or value.
↑Moves to the previous item or value.
HomeJumps to the first item or the minimum.
EndJumps to the last item or the maximum.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.