Stepper
A multi-step progress pattern with keyboard-accessible tabs, optional connectors, and per-step panels.
Step 2
Shipping
Choose the carrier, service level, and notification settings.
Installation
The components are exported from @by/experience-system. Add the package with your package manager:
pnpm add @by/experience-systemIn this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.
Composition
Use the following composition to build a stepper:
Stepper
├── StepperNav
│ ├── StepperItem
│ │ ├── StepperTrigger
│ │ │ ├── StepperIndicator
│ │ │ ├── StepperTitle (optional)
│ │ │ └── StepperDescription (optional)
│ │ └── StepperSeparator (optional)
│ └── StepperItem …
└── StepperPanel
└── StepperContent …Each StepperItem step number must match exactly one StepperContent value. StepperNav renders a tablist; each StepperTrigger is a tab. Props and semantics are documented in API Reference and mirror the implementation in packages/experience-system.
Usage
import {
Stepper,
StepperContent,
StepperDescription,
StepperIndicator,
StepperItem,
StepperNav,
StepperPanel,
StepperSeparator,
StepperTitle,
StepperTrigger,
} from '@by/experience-system';Stepper and its step parts are client components ('use client'). Use them inside a Client Component or a dynamic import when using the Next.js App Router.
<Stepper defaultValue={1}>
<StepperNav aria-label="Checkout">
<StepperItem step={1}>
<StepperTrigger>
<StepperIndicator>1</StepperIndicator>
<StepperTitle>Cart</StepperTitle>
<StepperDescription>Review items</StepperDescription>
</StepperTrigger>
<StepperSeparator />
</StepperItem>
<StepperItem step={2}>
<StepperTrigger>
<StepperIndicator>2</StepperIndicator>
<StepperTitle>Payment</StepperTitle>
<StepperDescription>Billing details</StepperDescription>
</StepperTrigger>
</StepperItem>
</StepperNav>
<StepperPanel>
<StepperContent value={1}>Cart panel</StepperContent>
<StepperContent value={2}>Payment panel</StepperContent>
</StepperPanel>
</Stepper>Examples
Overview
Horizontal layout with titles, descriptions, and panels. The second step is active by default (same preview as at the top of the page).
Step 2
Shipping
Choose the carrier, service level, and notification settings.
Vertical
Use orientation="vertical" on Stepper for a side rail or stacked setup flow; pair StepperNav with StepperPanel in your own flex layout as needed.
Step 1
Profile
Fill in the core profile information for the new account.
Item states
Use StepperItem error, disabled, and loading with optional indicators on the root (for example a spinner for loading).
Error and disabled
Loading on the active step
Workflow recipe
Controlled value with Card, footer actions, and a custom indicators.loading node—typical for multi-step business flows.
Step 2 of 4: Warehouse setup
Step 2
Warehouse setup
Select the warehouses included in the release and review storage, picking, and shipping defaults before operators start using the flow.
API Reference
Subsection titles name the exports from @by/experience-system. These tables mirror packages/experience-system/src/components/Stepper/Stepper.tsx (Experience System implementation, not a Radix primitive).
Stepper
Root provider and layout wrapper (div).
| Prop | Type | Default |
|---|---|---|
defaultValue | number | 1 |
value | number | — (controlled) |
onValueChange | (value: number) => void | — |
orientation | horizontal | vertical | horizontal |
indicators | StepperIndicators | {} |
StepperIndicators accepts optional ReactNode values for keys active, completed, inactive, loading, and error. When indicators.completed is omitted, a default check icon is applied for completed steps.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper |
data-orientation | horizontal | vertical |
StepperNav
Wrapper for step triggers. Renders role="tablist" and sets aria-orientation from the root orientation.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-nav |
data-orientation | horizontal | vertical |
StepperItem
Stateful wrapper for one step trigger and optional separator.
| Prop | Type | Default |
|---|---|---|
step | number | — (required, 1-based) |
completed | boolean | false |
disabled | boolean | false |
error | boolean | false |
loading | boolean | false |
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-item |
data-state | active | completed | inactive |
data-loading | present when loading is true on the active step |
data-error | present when error is true |
StepperTrigger
Focusable control for a step (button, role="tab").
Also accepts standard button attributes (for example onClick, onKeyDown, tabIndex).
| Data attribute | Values |
|---|---|
data-slot | stepper-trigger |
data-state | active | completed | inactive |
data-loading | present when the item is loading on the active step |
StepperIndicator
Circular indicator; shows indicators content for the current logical state, or children when no indicator override exists for that state.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-indicator |
data-state | active | completed | inactive | loading | error |
StepperSeparator
Connector line between adjacent steps.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-separator |
data-state | active | completed | inactive (from the parent item) |
StepperTitle
Primary label inside a trigger.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-title |
StepperDescription
Supporting text inside a trigger.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-description |
StepperPanel
Wrapper around all StepperContent panels.
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-panel |
StepperContent
Panel for a single step (role="tabpanel").
| Prop | Type | Default |
|---|---|---|
value | number | — (required, 1-based) |
forceMount | boolean | false |
Also accepts standard div attributes.
| Data attribute | Values |
|---|---|
data-slot | stepper-content |
data-state | active | inactive |
Accessibility
Follow the Tabs WAI-ARIA pattern: StepperNav is a tablist, each StepperTrigger is a tab with aria-selected and aria-controls, and each StepperContent is a tabpanel with aria-labelledby. Give StepperNav an accessible name (for example aria-label). In horizontal layout, Arrow Left / Arrow Right follow reading direction when ThemeProvider sets direction="rtl".
Keyboard interactions
| Key | Description |
|---|---|
ArrowRight | When orientation is horizontal, moves focus to the next enabled trigger (ltr); in rtl, moves to the visually next step. |
ArrowLeft | When orientation is horizontal, moves focus to the previous enabled trigger (ltr); in rtl, moves to the visually previous step. |
ArrowDown | When orientation is vertical, moves focus to the next enabled trigger. |
ArrowUp | When orientation is vertical, moves focus to the previous enabled trigger. |
Home | Moves focus to the first enabled trigger. |
End | Moves focus to the last enabled trigger. |
Enter / Space | Activates the focused step (respects disabled). |
Source in the repo: packages/experience-system/src/components/Stepper/Stepper.tsx. Agent-oriented contracts: packages/experience-system/src/components/Stepper/Stepper.instructions.md.