Skip to content

Commit 8e1f643

Browse files
committed
Add basic multi-step form
1 parent 7f2ba4d commit 8e1f643

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed

app/register_test/page.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"use client";
2+
3+
import {Suspense} from "react";
4+
import MultiStepForm from "@/components/MultiStepForm";
5+
6+
7+
export default function RegisterPage() {
8+
return (
9+
<Suspense fallback={<div></div>}>
10+
<RegisterComponent/>
11+
</Suspense>
12+
);
13+
}
14+
15+
function RegisterComponent() {
16+
17+
18+
return (
19+
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
20+
<MultiStepForm/>
21+
</div>
22+
);
23+
}

components/MultiStepForm.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React, {useState} from "react";
2+
import {useForm, SubmitHandler} from "react-hook-form";
3+
4+
type Question = {
5+
name: string;
6+
label: string;
7+
type?: string;
8+
options?: string[];
9+
};
10+
11+
const questions: Question[] = [
12+
{
13+
name: "firstName",
14+
label: "First Name"
15+
},
16+
{
17+
name: "lastName",
18+
label: "Last Name"
19+
},
20+
{
21+
name: "age",
22+
label: "Age",
23+
type: "number"
24+
},
25+
{
26+
name: "gender",
27+
label: "Gender",
28+
type: "select",
29+
options: ["Male", "Female", "Other"],
30+
},
31+
];
32+
33+
type FormValues = {
34+
[key: string]: any;
35+
};
36+
37+
const MultiStepForm: React.FC = () => {
38+
const [step, setStep] = useState(0);
39+
const {register, handleSubmit, getValues, formState: {errors}} = useForm<FormValues>();
40+
const isLastStep = step === questions.length - 1;
41+
42+
const onSubmit: SubmitHandler<FormValues> = (data) => {
43+
// handle final form submission
44+
alert(JSON.stringify(data, null, 2));
45+
};
46+
47+
const nextStep = () => setStep((s) => Math.min(s + 1, questions.length - 1));
48+
const prevStep = () => setStep((s) => Math.max(s - 1, 0));
49+
50+
const currentQuestion = questions[step];
51+
52+
return (
53+
<form onSubmit={handleSubmit(onSubmit)} className="mt-8 space-y-6">
54+
<div>
55+
<label className="px-4">{currentQuestion.label}</label>
56+
{currentQuestion.type === "select" ? (
57+
<select {...register(currentQuestion.name, {required: true})} className="px-4">
58+
<option value="">Select...</option>
59+
{currentQuestion.options?.map((opt) => (
60+
<option key={opt} value={opt}>{opt}</option>
61+
))}
62+
</select>
63+
) : (
64+
<input
65+
type={currentQuestion.type || "text"}
66+
{...register(currentQuestion.name, {required: true})}
67+
defaultValue={getValues(currentQuestion.name) || ""}
68+
/>
69+
)}
70+
{errors[currentQuestion.name] && <span>This field is required</span>}
71+
</div>
72+
<div style={{margin: 16,}}>
73+
{step > 0 && (
74+
<button type="button" onClick={prevStep} style={{margin: 16,}}>
75+
Back
76+
</button>
77+
)}
78+
{!isLastStep ? (
79+
<button
80+
type="button"
81+
onClick={() => {
82+
// Validate current step before proceeding
83+
handleSubmit(() => nextStep())();
84+
}}
85+
>
86+
Next
87+
</button>
88+
) : (
89+
<button type="submit">Submit</button>
90+
)}
91+
</div>
92+
</form>
93+
);
94+
};
95+
96+
export default MultiStepForm;
97+

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"next-themes": "^0.4.6",
4646
"react": "^19.1.0",
4747
"react-dom": "^19.0.0",
48+
"react-hook-form": "^7.62.0",
4849
"react-icons": "^5.5.0",
4950
"resend": "^4.7.0",
5051
"tailwind-merge": "^3.3.1",

0 commit comments

Comments
 (0)