ns-ui
A wizard stepper built as a flight of canal locks: the next chamber's water level climbs to meet the current one, and only once they equalize does the shared gate split open for the active highlight to glide through — an invalid step's level visibly stalls short of the gate line instead of popping a toast.
Use when Pick wizard-canal-lock for a multi-step form/wizard where a step's own validation should be the visible reason you can't advance — an unfilled next chamber literally won't rise to meet the gate. It's unrelated to confirm-dial-align (a lock-cylinder radio-group-pin unlock affordance) and hero-letterpress-lockup (a letterpress clamp interaction) — neither of those animates a precondition; wizard-canal-lock's whole mechanism is validation made physical across a sequence of steps, not a single lock's open/closed state.
Install
npx shadcn add https://design.helpmarq.com /r/wizard-canal-lock.jsonns-ui / wizard-canal-lock — a stepper where each gate only opens once the water equalizes
You’re creating a workspace for Acme Studio. Continue when you’re ready — this step has nothing left to fill in.
Continue past “Team” and the next chamber fills right to the gate line. Try it again past “Contact” without an email — the level stalls short, and the gate stays shut until you fill it in. Arrow keys move focus across the chambers; a locked chamber still explains why it’s locked to a screen reader.
| Prop | Type | Default | Description |
|---|---|---|---|
| steps | LockFlightStep[] | — | — |
| index? | number | — | controlled current step index; omit for uncontrolled |
| defaultIndex? | number | — | — |
| onIndexChange? | (index: number) => void | — | — |
| onComplete? | () => void | — | fires once when the final step is completed (Finish, while valid) |
| ariaLabel? | string | — | — |
| className? | string | — | — |