Stepper
A general-purpose, composition-based step indicator, decoupled from any form wizard. Compose Stepper with Step, StepIndicator, StepTitle, and StepDescription; the Stepper provides the active step via context and each step derives its completed, active, or upcoming state automatically.
Pro Features
Unlock advanced capabilities with the Pro version
Composition API
Assemble Stepper > Step > (StepIndicator + StepTitle + StepDescription) just like mature stepper libraries, with connectors added automatically
Controlled or Uncontrolled
Drive it with activeStep, or omit it and let defaultActiveStep plus internal state handle navigation — every step still derives completed / active / upcoming from its DOM index, with no per-step wiring
Two Orientations
Switch between horizontal and vertical layouts; the connectors and step alignment adapt automatically
Clickable Steps
Provide onStepClick and each step becomes a keyboard-accessible button that reports its index for navigable flows
Automatic Completed State
Completed steps render a check icon and a filled connector by default, so progress reads at a glance
Accessible & Token-Based
role="group", aria-current on the active step, and design-token colors that adapt to dark mode with no hardcoded values
Installation
Install via CLI
npx @moontra/moonui-cli add stepperUsage
Examples
Horizontal Stepper
The default orientation lays steps out in a row with automatic connectors between them. Completed steps show a check, the active step is highlighted, and upcoming steps stay neutral — all derived from activeStep.
Vertical Stepper
Set orientation="vertical" to stack steps with a vertical connector. Each step places the indicator on the left and the title and description in a column beside it.
Clickable Steps
Pass onStepClick to make every step a real, keyboard-accessible button. Clicking a step (or pressing Enter/Space when focused) reports its index — wire it to state to build a navigable flow.
Uncontrolled (defaultActiveStep)
activeStep is optional. Omit it and pass defaultActiveStep instead: the Stepper keeps the active index in internal state and advances it on click, so no useState in your component. onStepClick is still what makes the steps clickable — it now fires in addition to the internal update. Provide activeStep whenever you need to drive the flow from outside (validation, routing, Back/Next buttons); the two modes are mutually exclusive, activeStep always wins.
Click a step — the Stepper owns the active index itself; the state below only records your last click.
With Descriptions
Add a StepDescription under each StepTitle for extra context. It renders as muted helper text and works in both orientations.