Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Timeline

Show timeline with phase bands, a scrubbable playhead, cue markers, and a GO LIVE return action — promoted from the demo's status-bar timeline.

Import

Timeline is a registry composite — you own the source after installing:

npx ploxum add timeline
import { Timeline, type TimelineMarker, type TimelinePhase } from "@/components/timeline";

Depends on @roger-emerson/ploxum-primitives (StatusPip) and @roger-emerson/ploxum-utils (cn).

Usage

const phases: TimelinePhase[] = [
  { id: "doors", label: "Doors", startMinutes: 0, endMinutes: 90, tone: "info" },
  { id: "show", label: "Show", startMinutes: 90, endMinutes: 210, tone: "amber" },
  { id: "egress", label: "Egress", startMinutes: 210, endMinutes: 270, tone: "warning" },
];
 
const markers: TimelineMarker[] = [
  { id: "cue-12", label: "Pyro cue 12", atMinutes: 132, severity: "warning" },
  { id: "cue-47", label: "Headliner walk-on", atMinutes: 150, severity: "live" },
];
 
function ShowTimeline() {
  const [playhead, setPlayhead] = useState(164);
  const [live, setLive] = useState(true);
 
  return (
    <Timeline
      live={live}
      markers={markers}
      max={270}
      onGoLive={() => {
        setLive(true);
        setPlayhead(currentShowMinute());
      }}
      onScrub={(minutes) => {
        setLive(false);
        setPlayhead(minutes);
      }}
      phases={phases}
      value={playhead}
    />
  );
}

Fully controlled: value is the playhead position in minutes, onScrub fires as the operator drags the native range input. When live is false and onGoLive is provided, a GO LIVE button renders to snap back to real time.

Props

Timeline

PropTypeDefaultDescription
valuenumberCurrent playhead position in minutes.
maxnumberTotal show length in minutes.
onScrub(minutes: number) => voidFires as the playhead is dragged.
phasesTimelinePhase[][]Tinted bands behind the playhead, plus a legend row.
markersTimelineMarker[][]Cue markers rendered as StatusPips above the track.
livebooleantrueWhen false and onGoLive is provided, a GO LIVE button renders.
onGoLive() => voidReturn-to-live handler.
formatTime(minutes: number) => stringT+HH:MMFormat the elapsed readout.
classNamestringExtra classes on the root.
refRef<HTMLDivElement>Forwarded to the root.

TimelinePhase

FieldTypeDescription
idstringStable key.
labelstringPhase name; shown in the legend, highlighted while the playhead is inside the phase.
startMinutesnumberBand start.
endMinutesnumberBand end.
tone"info" | "amber" | "warning"Band color, drawn at 35% opacity behind the progress fill.

TimelineMarker

FieldTypeDescription
idstringStable key.
labelstringAccessible label + title tooltip.
atMinutesnumberPosition on the track.
severityStatusPipStatus?Pip shape + color; defaults to "unknown".

Design rules

  • The scrubber is a native <input type="range"> (styled thumb, amber glow) — keyboard arrow-key scrubbing and screen-reader value reporting come for free. Don't replace it with a pointer-only drag surface.
  • The elapsed readout (T+HH:MM) is monospace + tabular numerals; it must not shift layout as it ticks.
  • Phase bands sit at 0.35 opacity under the amber progress fill — they're context, not data. Don't raise their opacity to compete with the playhead.
  • Markers are StatusPips (shape + color), never bare colored dots.

Storybook

Composites/Timeline ↗