Data & tables
Timeline
Milestone & pipeline tracker with spring progress physics
detent-timeline
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 3
- Wave
- phase-3-data
- Group
- Data & tables
6.9 KB gzip for the class module
Variants
A local sample release pipeline. Activating a status node selects the step, toggles its detail panel and emits
detent-item-select; the progress rail fills to the last completed or in-progress step. The in-progress
node carries a decorative breathing aura, and prefers-reduced-motion: reduce removes it. The commit hash
button copies the full hash and shows a copied state for two seconds — nothing is fetched.
No step has been selected yet.
Recorded states
errorrecorded state; no setterexpandedrecorded state; no settercollapsedrecorded state; no setterreduced motionrecorded state; no settercompletedrecorded state; no setterpendingrecorded state; no setter
Usage
Import
import '/components/timeline/define.js';
// or register it yourself
import { DetentTimeline } from '/components/timeline/timeline.js';
Attributes
collapsibledefault-selected-id
Properties
itemsonItemSelect
Slots
No slots are recorded for this component.
Events
detent-item-select— {}
Example
Runnable example: site/examples/timeline.ts. The snippet below is generated from the catalogued attributes.
<detent-timeline
collapsible
default-selected-id
></detent-timeline>
Property-only values
const element = document.querySelector('detent-timeline');
if (element !== null) {
// items: TimelineItem[]
element.items = [];
// onItemSelect: (item: TimelineItem) => void
element.onItemSelect = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/InteractiveTimeline.tsxsha256 264bdd3db270…
Native files
The native module and its artifacts:
src/components/timeline/timeline.tssrc/components/timeline/styles.csssrc/components/timeline/define.tsdocs/components/timeline.mdsite/examples/timeline.tstests/browser/timeline.spec.tsevidence/components/timeline.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
collapsible | collapsible | boolean | true | Presence semantics: present means true, absent means false. |
default-selected-id | defaultSelectedId | string | items[0]?.id | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
items | TimelineItem[] | [] | Property-only: assign from script; not accepted as an attribute. |
onItemSelect | (item: TimelineItem) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-item-select | onItemSelect | (item: TimelineItem) => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The status node is the single disclosure control; upstream made the whole card a click div that also contained the copy <button> (nested interactive content). The card keeps a pointer affordance, but only the node owns aria-expanded and the keyboard path.
- Upstream rendered a title tooltip with <title> - <status>; the native port uses an aria-label with the same information so assistive technology gets it.
- The progress rail is a solid accent fill instead of the upstream #3B82F6 → transparent gradient, so its contrast is measurable; the animated springGentle height becomes a CSS transition that reduced motion removes.
- Upstream's hard-coded dark-only palette becomes theme tokens, and its lucide-react status icons (Check, Loader2, Clock, AlertCircle) become aria-hidden local SVG icons. They take the node's token colour (accent, muted or failed) instead of upstream's white, grey and rose, because the native node is not filled and white would vanish on it; each icon measures at least 3:1 against its node fill in light and dark. The in-progress icon spins unless reduced motion is requested.
- Copy commit hash is best-effort (the clipboard API needs a permission grant), keeps upstream's 2 s feedback and emits no event.
- commitHash is rendered as text, never parsed as a URL (a javascript: value stays inert text).
What it does
A milestone / pipeline tracker: a continuous progress line, interactive status nodes (completed, in-progress, pending, failed), and collapsible detail cards with a metrics grid, author metadata and a copyable commit hash.
Upstream behaviour
- Animated continuous progress line with spring physics
- Interactive status nodes (completed, in-progress, pending, failed) with breathing aura
- Collapsible details with metrics grid and commit metadata
- One-click commit hash copying with feedback state
- Accessible semantic list and keyboard navigation structure
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- The status node is the single disclosure control; upstream made the whole card a click div that also contained the copy <button> (nested interactive content). The card keeps a pointer affordance, but only the node owns aria-expanded and the keyboard path.
- Upstream rendered a title tooltip with <title> - <status>; the native port uses an aria-label with the same information so assistive technology gets it.
- The progress rail is a solid accent fill instead of the upstream #3B82F6 → transparent gradient, so its contrast is measurable; the animated springGentle height becomes a CSS transition that reduced motion removes.
- Upstream's hard-coded dark-only palette becomes theme tokens, and its lucide-react status icons (Check, Loader2, Clock, AlertCircle) become aria-hidden local SVG icons. They take the node's token colour (accent, muted or failed) instead of upstream's white, grey and rose, because the native node is not filled and white would vanish on it; each icon measures at least 3:1 against its node fill in light and dark. The in-progress icon spins unless reduced motion is requested.
- Copy commit hash is best-effort (the clipboard API needs a permission grant), keeps upstream's 2 s feedback and emits no event.
- commitHash is rendered as text, never parsed as a URL (a javascript: value stays inert text).