Experience System
Components

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-system

In 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

Resolve validation errors before continuing.

Loading on the active step

Content for the step that is loading.

Workflow recipe

Controlled value with Card, footer actions, and a custom indicators.loading node—typical for multi-step business flows.

Order rollout workflow
A recipe example showing how to compose the Stepper primitive into a multi-step business flow.

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).

PropTypeDefault
defaultValuenumber1
valuenumber— (controlled)
onValueChange(value: number) => void
orientationhorizontal | verticalhorizontal
indicatorsStepperIndicators{}

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 attributeValues
data-slotstepper
data-orientationhorizontal | vertical

StepperNav

Wrapper for step triggers. Renders role="tablist" and sets aria-orientation from the root orientation.

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-nav
data-orientationhorizontal | vertical

StepperItem

Stateful wrapper for one step trigger and optional separator.

PropTypeDefault
stepnumber— (required, 1-based)
completedbooleanfalse
disabledbooleanfalse
errorbooleanfalse
loadingbooleanfalse

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-item
data-stateactive | completed | inactive
data-loadingpresent when loading is true on the active step
data-errorpresent when error is true

StepperTrigger

Focusable control for a step (button, role="tab").

Also accepts standard button attributes (for example onClick, onKeyDown, tabIndex).

Data attributeValues
data-slotstepper-trigger
data-stateactive | completed | inactive
data-loadingpresent 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 attributeValues
data-slotstepper-indicator
data-stateactive | completed | inactive | loading | error

StepperSeparator

Connector line between adjacent steps.

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-separator
data-stateactive | completed | inactive (from the parent item)

StepperTitle

Primary label inside a trigger.

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-title

StepperDescription

Supporting text inside a trigger.

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-description

StepperPanel

Wrapper around all StepperContent panels.

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-panel

StepperContent

Panel for a single step (role="tabpanel").

PropTypeDefault
valuenumber— (required, 1-based)
forceMountbooleanfalse

Also accepts standard div attributes.

Data attributeValues
data-slotstepper-content
data-stateactive | 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

KeyDescription
ArrowRightWhen orientation is horizontal, moves focus to the next enabled trigger (ltr); in rtl, moves to the visually next step.
ArrowLeftWhen orientation is horizontal, moves focus to the previous enabled trigger (ltr); in rtl, moves to the visually previous step.
ArrowDownWhen orientation is vertical, moves focus to the next enabled trigger.
ArrowUpWhen orientation is vertical, moves focus to the previous enabled trigger.
HomeMoves focus to the first enabled trigger.
EndMoves focus to the last enabled trigger.
Enter / SpaceActivates 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.