The stepper instance
Understand the object that drives state, navigation, and rendering.
useStepper() returns a single flat object. Everything you read (current step,
index, progress) and everything you do (navigate, save values, complete steps)
lives directly on it — no nested state or navigation namespaces.
The fastest way to understand it is to drive one. Click the controls below and watch every value react in real time.
Drive a real instance
Every value below is read from useStepper(). Use the controls and watch them change.
const stepper = onboarding.useStepper();
- stepper.id
- "account"
- The active step's typed id.
- stepper.index
- 0
- Its position in the steps array.
- stepper.progress
- 0
- Position from 0 to 1. Not the share of completed steps.
- stepper.isFirst
- true
- At the start of the flow.
- stepper.isLast
- false
- At the end of the flow.
- stepper.canPrev
- false
- Bind it to your Back button's disabled state.
- stepper.canNext
- true
- Bind it to your Next button's disabled state.
- stepper.completed
- []
- Only what you marked complete. Moving never fills it.
Last call
Click a control. Navigation returns a typed result you can check.
Try this
- Point at Previous: it reads canPrev.
- Go forward: completed stays empty.
- Mark a step complete, then move: it stays marked.
What just happened
next()/prev()move the active step. Noticeindex,progress, and thecurrent.idchange together — they are all derived from one source.canPrev/canNextflip automatically at the edges. You never compute "am I on the last step?" yourself — bind buttons straight to them.setComplete()changescompletedbut leaves the position untouched. Completion is independent from where you are — see Status vs completion.goTo(id)(click any circle) jumps directly to a step by its typed id.
The mental model
Think of the instance as derived state over one pointer. You move the
pointer (the current index); everything else — current, progress, isLast,
each step's status — is recomputed for you.
const stepper = onboarding.useStepper();
stepper.current; // the active step object (with your custom fields)
stepper.index; // where the pointer is
stepper.next(); // move the pointer forward
stepper.match({ ... }); // render exactly the active stepYou only manage intent ("go next", "jump to review"). Stepperize manages the consequences.
The six you need on day one
Most flows ship with just these:
| Member | What it gives you |
|---|---|
current | The active step object, including your custom fields. |
match({...}) | Exhaustive, type-checked rendering by step id. |
next() / prev() | Move through the flow. |
canNext / canPrev | Ready-made disabled states for your buttons. |
Everything else — values, completion, events, step-map helpers — is there when you need it, and invisible until then. The full instance reference lists every member.
Next: the navigation lifecycle.
Last updated on