Skip to content

Stepper

The Stepper component provides a vertical progress indicator for multi-step workflows like wizards and onboarding flows. It supports dynamic nested steps, multiple visual states, transition animations, navigation guards, and keyboard navigation.

It is composed of Stepper.Root, Stepper.StepGroup, and Stepper.Step to offer a structured and customizable interface.

Variations

Step states

Steps display different visual states based on their position relative to the active step and explicit state overrides.

Loading and blocking

Steps can show a loading spinner and optionally block forward navigation while an async operation is in progress.

Nested steps

A Stepper.StepGroup can contain dynamic nested steps that appear when the group is active. Nested steps support conditional rendering based on application state.

Indeterminate nested steps

When a step group has hasNestedSteps but no children are provided, a placeholder indicator with ”…” is shown, signaling that nested steps will be determined dynamically (e.g., after an API call resolves).

Here’s an example combining real nested steps (.1, .2, .3) on the active step group with an indeterminate placeholder on a following step group:

Use the onBeforeChange prop to confirm navigation (e.g., warn users about losing progress when going back).

Completed state

When all steps are done, pass completed to show a “Complete” badge instead of the step counter. Completed steps still fade to 60% opacity by default so an in-progress step stays visually focused. For a finished flow that should stay fully opaque (no hover flash), pass disableCompletedFade.

Without connectors

Set showConnectors={false} to hide the vertical connector lines between steps.

Skeleton loading

When no children are passed, the stepper renders a skeleton placeholder. Control the number of skeleton items with skeletonCount.

Installation

import { Stepper } from "@harnessio/ui/components";
//...
const [currentStep, setCurrentStep] = useState("step-1");
return (
<Stepper.Root value={currentStep} onValueChange={setCurrentStep} title="Setup">
<Stepper.Step value="step-1" title="First Step" description="Do something" />
<Stepper.Step value="step-2" title="Second Step" description="Do another thing" />
<Stepper.Step value="step-3" title="Final Step" description="All done" />
</Stepper.Root>
)