Multi-Step Form
Blocks & SlicesA guided wizard block: a numbered role=progressbar header whose gradient fill springs along the track as you advance, step panels that cross-fade and slide in the travel direction while the panel height morphs to fit, and validation-gated Back/Next with a submit step that fires onComplete. Announces each step change through a polite live region and moves focus to the incoming heading; under prefers-reduced-motion steps swap instantly and the bar fills without transition.
Step 1 of 3, Create your account.
Step 1 of 3
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/multi-step-form.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/multi-step-form.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div className="w-full max-w-[440px]">
<MultiStepForm
steps={[
{
id: "account",
title: "Create your account",
validate: () => true,
content: (
<div className="space-y-3">
<div className="space-y-1.5">
<span className="flex items-center gap-1.5 text-xs font-medium text-white/50">
<Mail className="size-3.5" aria-hidden /> Work email
</span>
<div className="flex h-9 items-center rounded-lg border border-white/10 bg-white/[0.04] px-3 text-[13px] text-white/80">
jordan@parable.dev
</div>
</div>
<div className="space-y-1.5">
<span className="flex items-center gap-1.5 text-xs font-medium text-white/50">
<Lock className="size-3.5" aria-hidden /> Password
</span>
<div className="flex h-9 items-center rounded-lg border border-white/10 bg-white/[0.04] px-3 text-[13px] tracking-[0.3em] text-white/80">
••••••••
</div>
</div>
</div>
),
},
{
id: "workspace",
title: "Set up your workspace",
content: (
<div className="space-y-1.5">
<span className="flex items-center gap-1.5 text-xs font-medium text-white/50">
<Building2 className="size-3.5" aria-hidden /> Workspace name
</span>
<div className="flex h-9 items-center rounded-lg border border-white/10 bg-white/[0.04] px-3 text-[13px] text-white/80">
Parable Studio
</div>
<p className="pt-1 text-[12px] leading-relaxed text-white/45">
This is where your team collaborates. You can rename it anytime.
</p>
</div>
),
},
{
id: "review",
title: "Review & finish",
content: (
<div className="space-y-2.5">
<div className="flex items-center justify-between rounded-lg border border-white/10 bg-white/[0.03] px-3 py-2 text-[13px]">
<span className="text-white/50">Email</span>
<span className="text-white/80">jordan@parable.dev</span>
</div>
<div className="flex items-center justify-between rounded-lg border border-white/10 bg-white/[0.03] px-3 py-2 text-[13px]">
<span className="text-white/50">Workspace</span>
<span className="text-white/80">Parable Studio</span>
</div>
<p className="flex items-center gap-1.5 pt-1 text-[12px] text-white/45">
<Sparkles className="size-3.5 text-violet-300" aria-hidden /> Everything looks good — submit to create your account.
</p>
</div>
),
},
]}
/>
</div>Props
MultiStepFormProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">
| Prop | Type | Default | Description |
|---|---|---|---|
| steps* | WizardStep[] | — | Ordered steps the wizard walks through; the last one is the submit step. |
| onComplete | () => void | — | Fires when the final step passes validation and the form is submitted. |
| currentIndex | number | — | Controlled active-step index. Pair with `onIndexChange`. |
| defaultIndex | number | 0 | Uncontrolled initial active-step index. |
| onIndexChange | (index: number) => void | — | Fires with the next index on Back / Next / step-marker navigation. |
| accent | string | "#8b5cf6" | Accent hex — progress fill, active marker, focus ring. Mirrors `--pb-violet`. |
| background | string | "#0f0f10" | Card surface colour. Mirrors the site `--pb-ink` token. |
| backLabel | React.ReactNode | "Back" | Label for the back button. |
| nextLabel | React.ReactNode | "Continue" | Label for the advance button on non-final steps. |
| submitLabel | React.ReactNode | "Submit" | Label for the advance button on the final step. |
npm dependencies
- motion
- lucide-react