Stepper

Multi-step flow with an active ring that glides between step markers, connectors that fill as steps complete, panels that slide in from the direction of travel while the container morphs to each panel's height, and an async per-step guard that shakes the marker when it refuses. Linear or free navigation, controlled/uncontrolled, reduced-motion safe.

Preview

Stepper preview width

Install

Add it with the shadcn CLI, or copy the source manually.

$ bunx --bun shadcn add @karaui/stepper
@karaui not found? Add it to components.json
{
  "registries": {
    "@karaui": "https://karaui.kamisama-v0.my.id/r/{name}.json"
  }
}

@karaui is in shadcn's public registry directory, so the latest CLI needs no setup. On an older CLI, merge this into the existing file once and every @karaui/… install resolves.

API Reference

Stepper

steps
StepperStep[]
—
value?
number

Controlled active step index.

—
defaultValue?
number

Uncontrolled initial step index. Default 0.

0
onValueChange?
((index: number) => void)
—
canAdvance?
StepperGuard

Runs before leaving a step forward (Next, or jumping ahead).

—
onComplete?
(() => void | Promise<void>)

Called when Next is pressed on the last step and its guard passes.

—
linear?
boolean

Linear (default): the indicator only jumps back, or forward to steps already reached. Non-linear: any step, still guarded by `canAdvance`.

true
className?
string
—

StepperIndicator

showTitles?
boolean

Show each step's title under its marker. Default true.

true
className?
string
—

StepperPanels

children
ReactNode

One child per step, in step order.

—
className?
string
—

StepperPrevious

className?
string
—
variant?
"primary" | "secondary" | "ghost" | "outline"
ghost
size?
"sm" | "md" | "lg" | "icon"
—
pressScale?
number
—
ripple?
boolean

Spawn a Material-style ripple from the press point. Off by default.

—

StepperNext

finishLabel?
ReactNode

Label on the last step. Default "Finish".

Finish
className?
string
—
variant?
"primary" | "secondary" | "ghost" | "outline"
—
size?
"sm" | "md" | "lg" | "icon"
—
pressScale?
number
—
ripple?
boolean

Spawn a Material-style ripple from the press point. Off by default.

—

Updated