Wizard
A steps + pager wizard that manages index state internally — visited steps can be revisited, future steps are locked
Installation
Usage
Basic Usage
Pass steps for the progress indicator and children for the pager body — one child per step. The Wizard manages index and maxIndex internally; visited steps can be revisited via the Steps indicator, future steps cannot be skipped ahead.
- Account
- Profile
- Confirm
"use client";
import { Wizard } from "@/ui";
const steps = [{ title: "Account" }, { title: "Profile" }, { title: "Confirm" }];
export default function WizardBasicDemo() {
return (
<Wizard steps={steps} onFinish={() => window.alert("Submitted")}>
<form className="flex h-full w-full flex-col justify-center gap-3 rounded-lg border p-4">
<label className="text-sm font-medium">Email</label>
<input
className="h-9 rounded-md border bg-background px-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
placeholder="[email protected]"
/>
<label className="text-sm font-medium">Password</label>
<input
type="password"
className="h-9 rounded-md border bg-background px-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
placeholder="••••••••"
/>
</form>
<form className="flex h-full w-full flex-col justify-center gap-3 rounded-lg border p-4">
<label className="text-sm font-medium">Display name</label>
<input
className="h-9 rounded-md border bg-background px-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
placeholder="Your name"
/>
<label className="text-sm font-medium">Bio</label>
<textarea
className="min-h-16 rounded-md border bg-background px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
placeholder="Tell something about yourself"
/>
</form>
<div className="flex h-full w-full flex-col items-center justify-center gap-2 rounded-lg border p-4">
<p className="text-sm font-medium">Ready to submit</p>
<p className="max-w-64 text-center text-sm text-muted-foreground">
Review your account and profile information, then submit the form.
</p>
</div>
</Wizard>
);
}
Notes
- Wizard internally uses Steps and Pager — when installing via CLI, add all:
litefy add wizard steps pager. - The Pager is configured with
gesture={false}andtransition="view-transition"to prevent accidental swipe submission and animate step transitions. maxIndextracks the highest visited step and is passed to Steps — visited steps are clickable for backward navigation, future steps are locked.- The last step swaps the Next button for Submit, which fires
onFinish.
Inline Variant
Wizard.Inline (also exported as InlineWizard) drives the same state machine as a vertical steps accordion: only the current step expands to show its content with its own Back / Continue controls, while the other steps stay collapsed to their title rows. Click a visited step to return to it.
- AccountCreate your login
- ProfileTell us a bit about yourself
- ConfirmReview and finish
"use client";import * as React from "react";import { InlineWizard } from "@/ui";export default function Demo() { const [username, setUsername] = React.useState(""); const [finished, setFinished] = React.useState(false); return ( <div className="w-full max-w-md"> <InlineWizard steps={[ { title: "Account", description: "Create your login", content: ( <input value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" className="w-full rounded-md border bg-transparent px-2 py-1 text-sm" /> ), }, { title: "Profile", description: "Tell us a bit about yourself", content: ( <p className="text-muted-foreground"> Profile details would be collected here. </p> ), }, { title: "Confirm", description: "Review and finish", content: ( <p className="text-muted-foreground"> Review your setup for <span className="font-medium">{username || "—"}</span>. </p> ), }, ]} onFinish={() => setFinished(true)} /> {finished && ( <p className="mt-3 text-sm text-success">Wizard finished — reload to restart.</p> )} </div> );}| Prop | Type | Default | Description |
|---|---|---|---|
steps | { title?; description?; content: React.ReactNode }[] | - | Step definitions. Required |
defaultIndex / index | number | 0 | Step index (uncontrolled / controlled) |
onIndexChange | (index: number) => void | - | Step change callback |
onFinish | () => void | - | Finish button callback on the last step |
maxIndex | number | last step | Furthest reachable step |
backLabel / nextLabel / finishLabel | React.ReactNode | "Back" / "Continue" / "Finish" | Button labels |
disabled | boolean | false | Disable navigation |
className | ClassNameValue | - | Custom classes, applied to the list |
classNames | marker / title / description / connector / content / footer / button / primaryButton | - | Custom classes per part |
API Reference
useWizardNavigation
The wizard state machine (clamped navigation + max-visited lock) is exported as useWizardNavigation({ count, defaultIndex?, index?, maxIndex?, onIndexChange? }) — it returns { index, maxVisited, maxReachable, isFirst, isLast, isReachable, go }. It powers both the pager-based Wizard above and the inline variant below, and you can use it to build custom wizard shells.
Wizard
A wizard component that manages step navigation state and renders Steps indicator, Pager body, and footer buttons.
| Prop | Type | Default | Description |
|---|---|---|---|
steps | StepsItemConfig[] | - | Step configurations for the progress indicator |
children | React.ReactNode[] | - | Page content, one child per step |
onFinish | () => void | - | Fired when the Submit button is clicked |
className | ClassNameValue | - | Custom class names, applied to the root |
classNames | { root? / steps? / pager? / footer? } | - | Custom class names per slot |