Stepper Navigation
Multi-step form with a visual stepper component synced to the wizard.
"use client";
import {
Stepper,
StepperIndicator,
StepperItem,
StepperTitle,
StepperTrigger,
} from "@tilt-legal/cubitt-components/stepper";
import { z } from "zod";
import { FormBuilder } from "@tilt-legal/cubitt-components/form-builder";
const schema = z.object({
client: z.object({
name: z.string().min(1),
email: z.string().email(),
}),
engagement: z.object({
type: z.enum(["standard", "custom"]),
startDate: z.date(),
}),
confirm: z.boolean().refine(Boolean),
});
type WizardValues = z.infer<typeof schema>;
const formDefs = [
{
kind: "step",
id: "client",
title: "Client details",
children: [/* fields */],
},
{
kind: "step",
id: "engagement",
title: "Engagement",
children: [/* fields */],
},
{
kind: "step",
id: "confirm",
title: "Confirm",
children: [/* fields */],
},
] as const satisfies FormDefs<WizardValues>;
export default function StepperNavForm() {
const stepper = FormBuilder.Single.useStepper<WizardValues>(
(slot) => slot.defaultStepper
);
const steps = formDefs.filter((n) => n.kind === "step");
return (
<div>
<Stepper
value={stepper.state.index}
onValueChange={(idx) => stepper.actions.goTo(idx)}
className="mb-8"
>
{steps.map((step, idx) => (
<StepperItem
key={step.id}
step={idx}
disabled={idx > stepper.state.index}
>
<StepperTrigger>
<StepperIndicator />
<StepperTitle>{step.title}</StepperTitle>
</StepperTrigger>
</StepperItem>
))}
</Stepper>
<FormBuilder.Single
schema={schema}
formDefs={formDefs}
defaultValues={{...}}
stepper={stepper.render}
onSubmit={async (values) => console.log(values)}
/>
</div>
);
}How It Works
- Keep default footer – Pass
(slot) => slot.defaultStepperto preserve Next/Back buttons - Sync with Stepper – Bind
valuetostepper.state.indexandonValueChangetostepper.actions.goTo - Disable future steps – Prevent jumping ahead with
disabled={idx > stepper.state.index}
The key difference from Multi-Step Wizard:
() => null– Hides default UI for fully custom navigation(slot) => slot.defaultStepper– Keeps default footer, lets you add a visual progress indicator
See Stepper Hook for the full API and the Stepper component for styling options.