Search

Search the site

All components

Multi Step Form

A multi step form component

Default
Default multi step form
Profile

Tell us how to contact you.

1
Profile
2
Plan
3
Notes
1"use client";
2
3import { useMemo, useState } from "react";
4import { useFormContext } from "react-hook-form";
5import { z } from "zod";
6import { MultiStepForm } from "@/registry/ui";
7import { Input } from "@/components/ui/input";
8import { Label } from "@/components/ui/label";
9import { Textarea } from "@/components/ui/textarea";
10
11type DemoValues = {
12 fullName?: string;
13 email?: string;
14 company?: string;
15 plan?: string;
16 notes?: string;
17};
18
19const ProfileStep = () => {
20 const { register } = useFormContext<DemoValues>();
21
22 return (
23 <div className="space-y-4">
24 <div className="space-y-2">
25 <Label htmlFor="fullName">Full name</Label>
26 <Input
27 id="fullName"
28 placeholder="Ada Lovelace"
29 {...register("fullName")}
30 />
31 </div>
32 <div className="space-y-2">
33 <Label htmlFor="email">Email</Label>
34 <Input
35 id="email"
36 type="email"
37 placeholder="ada@example.com"
38 {...register("email")}
39 />
40 </div>
41 </div>
42 );
43};
44
45const PlanStep = () => {
46 const { register } = useFormContext<DemoValues>();
47
48 return (
49 <div className="space-y-4">
50 <div className="space-y-2">
51 <Label htmlFor="company">Company</Label>
52 <Input
53 id="company"
54 placeholder="Analytical Engines Inc."
55 {...register("company")}
56 />
57 </div>
58 <div className="space-y-2">
59 <Label htmlFor="plan">Plan</Label>
60 <Input
61 id="plan"
62 placeholder="Starter / Pro / Enterprise"
63 {...register("plan")}
64 />
65 </div>
66 </div>
67 );
68};
69
70const NotesStep = () => {
71 const { register } = useFormContext<DemoValues>();
72
73 return (
74 <div className="space-y-2">
75 <Label htmlFor="notes">Anything else?</Label>
76 <Textarea
77 id="notes"
78 placeholder="Share context for your setup..."
79 className="min-h-28"
80 {...register("notes")}
81 />
82 </div>
83 );
84}
85
86export function MultiStepFormDefaultExample() {
87 const [submittedData, setSubmittedData] = useState<DemoValues | null>(null);
88
89 const steps = useMemo(
90 () => [
91 {
92 id: "profile",
93 title: "Profile",
94 description: "Tell us how to contact you.",
95 component: <ProfileStep />,
96 validationSchema: z.object({
97 fullName: z.string().min(2, "Name is too short"),
98 email: z.string().email("Please enter a valid email"),
99 }),
100 },
101 {
102 id: "plan",
103 title: "Plan",
104 description: "Share your team details.",
105 component: <PlanStep />,
106 validationSchema: z.object({
107 company: z.string().min(2, "Company is required"),
108 plan: z.string().min(2, "Plan is required"),
109 }),
110 },
111 {
112 id: "notes",
113 title: "Notes",
114 description: "Optional context before submission.",
115 component: <NotesStep />,
116 isOptional: true,
117 },
118 ],
119 [],
120 );
121
122 return (
123 <div className="space-y-4 w-full">
124 <MultiStepForm
125 steps={steps}
126 onSubmit={(data) => setSubmittedData(data)}
127 storageKey="multi-step-form-example"
128 />
129
130 {submittedData ? (
131 <pre className="rounded-lg border bg-muted/30 p-4 text-xs">
132 {JSON.stringify(submittedData, null, 2)}
133 </pre>
134 ) : null}
135 </div>
136 );
137}

Installation & source

Install via the shadcn CLI or copy the registry files manually.

bash
npx shadcn@latest add @tt-ui/multi-step-form

Props

NameTypeDefaultDescription
stepsarrayRequiredThe steps of the form
initialDataobject{}The initial data of the form
onSubmitfunctionRequiredThe function to submit the form
classNamestringThe class name of the form
storageKeystringmulti-step-formThe key to store the form data in localStorage