Navigation
Stepper
Animated connector line, gliding focus ring, and step panels
detent-stepper
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 2
- Wave
- phase-2-navigation
- Group
- Navigation
6.7 KB gzip for the class module
Variants
Recorded states
activerecorded state; no settercompletedrecorded state; no setter
Usage
Import
import '/components/stepper/define.js';
// or register it yourself
import { DetentStepper } from '/components/stepper/stepper.js';
Attributes
currentorientation
Properties
stepscurrentorientationonStepChange
Slots
default
Events
detent-step-change— { index: number }
Example
Runnable example: site/examples/stepper.ts. The snippet below is generated from the catalogued attributes.
<detent-stepper
current="0"
orientation="horizontal"
></detent-stepper>
Property-only values
const element = document.querySelector('detent-stepper');
if (element !== null) {
// steps: Step[]
element.steps = [];
// onStepChange: (index: number) => void
element.onStepChange = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/stepper.tsxsha256 ec717f06b1b2…
Native files
The native module and its artifacts:
src/components/stepper/stepper.tssrc/components/stepper/styles.csssrc/components/stepper/define.tsdocs/components/stepper.mdsite/examples/stepper.tstests/browser/stepper.spec.tsevidence/components/stepper.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 |
|---|---|---|---|---|
current | current | number | 0 | Kebab-case attribute; camelCase property. |
orientation | orientation | 'horizontal' | 'vertical' | 'horizontal' | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
steps | Step[] | undefined | Property-only: assign from script; not accepted as an attribute. |
current | number | 0 | Property-only: assign from script; not accepted as an attribute. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Property-only: assign from script; not accepted as an attribute. |
onStepChange | (index: number) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-step-change | onStepChange | (index: number) => void | Composed, bubbles; fires only for a user action. |
Slots
| Slot | Notes |
|---|---|
default | Consumer content; rendered through a slot, never re-created. |
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.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `StepPanels` folds into `detent-stepper` as the `default` slot contract and is published as a TYPE, not a second tag (the row records one tag and one slot, PC-13.1).
- Completed steps are always buttons (upstream only when `onStepChange` was passed, which is undetectable natively); activating one moves focus to that step's static body instead of dropping focus on document body (PC-5.1).
- The ring glides with the upstream code-local spring (420/34/0.8) via the shared helper, not a recorded token; the connector fill keeps upstream fixed timing (350ms) and the panel slide 180ms.
- The completed check is static (upstream path-draw is decorative); `className` maps to parts and `React.Children` to the `default` slot.
- `current` is reflected, and a programmatic write animates like a user activation without emitting an event.
- Upstream neutral-* pairs become --detent-color-*; inactive steps are muted but never faded.
What it does
A progress trail with a connector that fills as you advance, a single ring that glides to the active step, clickable completed steps, and a direction-aware panel slide for slotted content.
Upstream behaviour
- Connector line fills smoothly as you advance through steps
- A single active indicator ring glides between steps using Framer Motion layoutId
- Completed step checkmark animates its stroke path on completion
- Direction-aware StepPanels: slides left/right depending on forward or backward navigation
- Horizontal and vertical layouts, clickable completed steps, and responsive mobile labels
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.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `StepPanels` folds into `detent-stepper` as the `default` slot contract and is published as a TYPE, not a second tag (the row records one tag and one slot, PC-13.1).
- Completed steps are always buttons (upstream only when `onStepChange` was passed, which is undetectable natively); activating one moves focus to that step's static body instead of dropping focus on document body (PC-5.1).
- The ring glides with the upstream code-local spring (420/34/0.8) via the shared helper, not a recorded token; the connector fill keeps upstream fixed timing (350ms) and the panel slide 180ms.
- The completed check is static (upstream path-draw is decorative); `className` maps to parts and `React.Children` to the `default` slot.
- `current` is reflected, and a programmatic write animates like a user activation without emitting an event.
- Upstream neutral-* pairs become --detent-color-*; inactive steps are muted but never faded.