For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt, and this page is available as Markdown at https://wallarm.github.io/design-system/components/stepper.md.

Stepper

A horizontal row of numbered steps for a flow that is split into a few screens, such as a create drawer — it shows where the reader is and lets them jump to any step. It is compound, like Ark UI Steps: count on the root and index on every StepperItem and StepperContent are explicit. StepperContent shows the current step’s body, and StepperPrevTrigger / StepperNextTrigger move between steps; Next stops at the last step, where the page renders its own submit button. It never blocks a step: the page owns each step’s status (completed, danger, upcoming), and the current step always renders as active. Reach for Timeline for a history of events, Tour for guided onboarding, Progress for how far along a task is, and Tabs for sections that have no order.

Source · Storybook

Usage

import { Stepper, StepperIndicator, StepperItem, StepperList, StepperSeparator, StepperTitle, StepperTrigger } from '@wallarm-org/design-system/Stepper';

Examples

Step types

The four step types: the page sets completed, danger or upcoming, and the current step is always active — a current danger step (Scope) shows as active too, since active is the only step in brand.

With description

An optional second line under the title; the separator stays on the first row.

Controlled with step and onStepChange; every step is clickable, back and forward.

In drawer

Inside a create drawer: the step list sits under the header, StepperContent shows the current step's body (every body stays mounted, so fields keep their values) and the footer moves with Back / Next. Steps never submit the form; only the last step's own submit button does. Focus stays on the footer when Back or Next unmounts. The list sits directly below the header, with 24px side insets, 12px bottom padding and no divider. Drawer parts inside the Stepper root take its test ids (stepper--body, stepper--footer), not the Drawer's.

Long label

A title over 320px ellipsizes, with the full text in a tooltip on hover; so does a long description.

Six steps

Six steps, the most the design supports — at full width, then in a 640px drawer where titles truncate earlier.

The footer recipe: StepperPrevTrigger on the left (hidden on the first step) and StepperNextTrigger as Next: <destination> on the right, both asChild with a Button. On the last step the page renders its own submit button instead: Next is disabled there. When Back or Next unmounts under the keyboard, the page moves focus to the right-hand footer button (useFooterFocus here), so it never falls to <body>.

Custom indicator

children on StepperIndicator replaces the number, ! or check, here with an icon on a locked step.

Analytics and test ids

data-analytics-id and data-analytics-props land on each step's button and on the Back / Next buttons, and data-testid cascades from the root ({id}--item-{index}--trigger) unless a part sets its own.

Props

PropTypeDefaultDescription
statusLabelsStepperStatusLabels | undefinedScreen-reader-only suffixes for completed and danger steps.
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
idsElementIds | undefinedThe custom ids for the stepper elements
count *numberNumber of steps, 1–6. Required: each StepperItem and StepperContent takes its index.
stepnumber | undefinedControlled current step, 0-based. Clamped to [0, count - 1].
defaultStepnumber | undefinedUncontrolled initial step. Default 0. Clamped to [0, count - 1].
onStepChange((details: StepChangeDetails) => void) | undefinedFires when a click changes the step, back or forward: ({ step }) => void. A click on the current step does not fire it; use the trigger's onClick to observe that.
data-testidstring | undefined

StepperContent

PropTypeDefaultDescription
index *number0-based step this body belongs to.
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperDescription

PropTypeDefaultDescription
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperIndicator

PropTypeDefaultDescription
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperItem

PropTypeDefaultDescription
index *number0-based position of this step. Required, like Ark's Steps.Item.
statusStepperItemStatus | undefinedStatus set by the page. Ignored while this item is the current step. Default 'upcoming'.
statusLabelstring | undefinedOverrides the root statusLabels suffix for this item.
valuestring | number | readonly string[] | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperList

PropTypeDefaultDescription
type"a" | "i" | "1" | "A" | "I" | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperNextTrigger

PropTypeDefaultDescription
asChildboolean | undefinedRender the child (e.g. a Button) as the trigger instead of a plain <button>.
disabledboolean | undefined
namestring | undefined
type"button" | "submit" | "reset" | undefined
valuestring | number | readonly string[] | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperPrevTrigger

PropTypeDefaultDescription
asChildboolean | undefinedRender the child (e.g. a Button) as the trigger instead of a plain <button>.
disabledboolean | undefined
namestring | undefined
type"button" | "submit" | "reset" | undefined
valuestring | number | readonly string[] | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperRootProvider

PropTypeDefaultDescription
value *complexThe machine from useStepper(), so the page can drive the steps from outside.
statusLabelsStepperStatusLabels | undefinedScreen-reader-only suffixes for completed and danger steps.
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperSeparator

PropTypeDefaultDescription
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperTitle

PropTypeDefaultDescription
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
titlestring | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

StepperTrigger

PropTypeDefaultDescription
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
disabledboolean | undefined
namestring | undefined
valuestring | number | readonly string[] | undefined
data-testidstring | undefined

Explorer