Search documentation

Search Stepper docs, API, guides, and release notes.

api

Stepper API

The V1 API keeps the surface small: one root, one ordered list, item primitives, content panels, and previous/next helpers.

Root props

PropTypeDefaultDescription
valuestring-Controlled active step value.
defaultValuestring-Initial active step for uncontrolled usage.
onValueChange(value: string) => void-Called when the selected step changes, including controlled fallbacks to the first enabled step.
orientation"horizontal" | "vertical""horizontal"Controls list layout and connector direction.
steps{ value: string; disabled?: boolean }[]-Optional explicit step list for headless, dynamic, or conditional flows. When provided, Stepper uses it instead of composed StepperItem registration order.

Controlled fallback

Controlled values are still normalized to an enabled step so the UI never points at missing or disabled content.

Missing value
First enabled step
When value points to a step that does not exist, Stepper renders the first enabled step and calls onValueChange with that fallback.
Disabled value
Skipped
When the selected step becomes disabled, Stepper moves to the first enabled step so controls and content stay coherent.
Real flows
App derived
For routes, forms, and server data, derive value from the app state instead of treating Stepper as the workflow owner.

List props

PropTypeDefaultDescription
aria-labelstring"Progress steps"Accessible name for the ordered list. Use aria-labelledby when the list has an external heading.

Item props

PropTypeDefaultDescription
valuestring-Unique step id used to connect trigger and content.
completedbooleanfalseMarks a step as completed and updates data-state.
defaultTriggerbooleantrueControls whether StepperItem renders the default trigger markup. Set it to false when composing your own StepperTrigger.
disabledbooleanfalseDisables the trigger and skips the step in next/previous navigation.
errorbooleanfalseMarks a step as needing attention and exposes data-state="error".
separatorbooleantrueControls the default connector separator after this item. Set to false when rendering a custom StepperSeparator.

Trigger props

PropTypeDefaultDescription
asChildbooleanfalseRender the trigger props onto a custom button or link with Radix Slot.
disabledbooleanfalseDisables the trigger in addition to the parent StepperItem disabled state. With asChild, aria-disabled and tabIndex are applied instead of a native disabled attribute.

asChild requirements

StepperTrigger and navigation helpers use Radix Slot composition. The child owns the final element, so it must accept the props Stepper passes.

Focusable child
button or link
StepperTrigger asChild should render a focusable element that can receive keyboard focus.
Prop forwarding
className and aria-*
Custom components must spread props so state attributes, classes, events, and ARIA props reach the real element.
Refs and events
forwardRef
Forward refs for custom components and avoid preventDefault unless you intentionally block navigation.

Content props

PropTypeDefaultDescription
valuestring-Step value this content panel belongs to.
forceMountbooleanfalseKeeps inactive content mounted and hidden. Prefer keepMounted for form persistence semantics.
keepMountedbooleanfalseSemantic alias for forceMount, useful when preserving form or adapter state between steps.
asChildbooleanfalseRender the content props onto a child element with Radix Slot.

Accessibility model

Stepper uses progress-step semantics instead of tab semantics, so it can safely compose with forms, route links, and validation gates.

Current step
aria-current="step"
The active trigger is announced as the current step in a related step list.
Keyboard
Arrows, Home, End
Arrow keys move focus between enabled triggers; Enter and Space keep the native button/link activation model.
Panels
aria-labelledby
StepperContent renders a region labelled by its trigger and can stay mounted with forceMount.
Semantics
Not tabs
Stepper avoids tab roles because it can represent route changes, validation gates, or progress indicators.

useStepper hook

Use the public hook for custom footers, async validation controls, or buttons outside the visual list.

PropTypeDefaultDescription
valuestring | undefined-Current active step after fallback resolution.
steps{ value: string; disabled: boolean }[]-Registered step order used by navigation helpers.
currentIndexnumber-Zero-based index for the current active step, or -1 when no enabled step is active.
totalStepsnumber-Total number of registered steps, including disabled steps.
setValue(value: string) => void-Selects an enabled step by value.
canGoPrevious / canGoNextboolean-Whether previous or next enabled steps exist.
goPrevious / goNext() => void-Moves to the previous or next enabled step.
wizard-footer.tsx
Copy code is available in the top right.
function WizardFooter() {
  const {
    canGoPrevious,
    canGoNext,
    currentIndex,
    totalSteps,
    goPrevious,
    goNext,
  } = useStepper();

  return (
    <div className="flex items-center justify-between">
      <span className="text-sm text-muted-foreground">
        Step {currentIndex + 1} of {totalSteps}
      </span>
      <div className="flex gap-2">
        <Button type="button" variant="outline" disabled={!canGoPrevious} onClick={goPrevious}>
          Back
        </Button>
        <Button type="button" disabled={!canGoNext} onClick={goNext}>
          Continue
        </Button>
      </div>
    </div>
  );
}

Primitive parts

Each part exposes data-slot and data-state attributes for predictable styling.

Stepper
Root provider that owns value, orientation, step order, and navigation state.
div
StepperList
Ordered visual list of steps. Supports horizontal and vertical layout.
ol
StepperItem
Step record with value, completed, disabled, and error states.
li
StepperTrigger
Real button by default. Can use asChild for custom triggers while keeping step selection logic.
button / Slot
StepperIndicator
Visual number, completed mark, error marker, or custom icon slot for a step.
span
StepperLabel
Text label primitive for custom triggers and composable layouts.
span
StepperDescription
Supporting text primitive for vertical steppers and richer step summaries.
span
StepperSeparator
Connector line between steps. Hidden automatically when rendered in the final item.
span
StepperContent
Associated panel for a step value. Can stay mounted with forceMount or render asChild.
div / Slot
StepperPrevious / StepperNext
Navigation helpers that skip disabled steps, support asChild, and can run async guards.
button / Slot
useStepper
Public hook for external form footers, validation controls, and custom navigation.
hook

Composable trigger

composable-trigger.tsx
Copy code is available in the top right.
<StepperItem value="shipping" defaultTrigger={false}>
  <StepperTrigger>
    <StepperIndicator />
    <span className="flex flex-col gap-1">
      <StepperLabel>Shipping</StepperLabel>
      <StepperDescription>Delivery address</StepperDescription>
    </span>
  </StepperTrigger>
</StepperItem>