Add basic multi-step form

This commit is contained in:
MartinBraquet
2025-08-05 20:19:11 +02:00
parent 7f2ba4d727
commit 8e1f643612
4 changed files with 137 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
"use client";
import {Suspense} from "react";
import MultiStepForm from "@/components/MultiStepForm";
export default function RegisterPage() {
return (
<Suspense fallback={<div></div>}>
<RegisterComponent/>
</Suspense>
);
}
function RegisterComponent() {
return (
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<MultiStepForm/>
</div>
);
}

View File

@@ -0,0 +1,97 @@
import React, {useState} from "react";
import {useForm, SubmitHandler} from "react-hook-form";
type Question = {
name: string;
label: string;
type?: string;
options?: string[];
};
const questions: Question[] = [
{
name: "firstName",
label: "First Name"
},
{
name: "lastName",
label: "Last Name"
},
{
name: "age",
label: "Age",
type: "number"
},
{
name: "gender",
label: "Gender",
type: "select",
options: ["Male", "Female", "Other"],
},
];
type FormValues = {
[key: string]: any;
};
const MultiStepForm: React.FC = () => {
const [step, setStep] = useState(0);
const {register, handleSubmit, getValues, formState: {errors}} = useForm<FormValues>();
const isLastStep = step === questions.length - 1;
const onSubmit: SubmitHandler<FormValues> = (data) => {
// handle final form submission
alert(JSON.stringify(data, null, 2));
};
const nextStep = () => setStep((s) => Math.min(s + 1, questions.length - 1));
const prevStep = () => setStep((s) => Math.max(s - 1, 0));
const currentQuestion = questions[step];
return (
<form onSubmit={handleSubmit(onSubmit)} className="mt-8 space-y-6">
<div>
<label className="px-4">{currentQuestion.label}</label>
{currentQuestion.type === "select" ? (
<select {...register(currentQuestion.name, {required: true})} className="px-4">
<option value="">Select...</option>
{currentQuestion.options?.map((opt) => (
<option key={opt} value={opt}>{opt}</option>
))}
</select>
) : (
<input
type={currentQuestion.type || "text"}
{...register(currentQuestion.name, {required: true})}
defaultValue={getValues(currentQuestion.name) || ""}
/>
)}
{errors[currentQuestion.name] && <span>This field is required</span>}
</div>
<div style={{margin: 16,}}>
{step > 0 && (
<button type="button" onClick={prevStep} style={{margin: 16,}}>
Back
</button>
)}
{!isLastStep ? (
<button
type="button"
onClick={() => {
// Validate current step before proceeding
handleSubmit(() => nextStep())();
}}
>
Next
</button>
) : (
<button type="submit">Submit</button>
)}
</div>
</form>
);
};
export default MultiStepForm;

16
package-lock.json generated
View File

@@ -40,6 +40,7 @@
"next-themes": "^0.4.6",
"react": "^19.1.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.62.0",
"react-icons": "^5.5.0",
"resend": "^4.7.0",
"tailwind-merge": "^3.3.1",
@@ -13538,6 +13539,21 @@
"react": "^19.1.1"
}
},
"node_modules/react-hook-form": {
"version": "7.62.0",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz",
"integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==",
"engines": {
"node": ">=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",

View File

@@ -45,6 +45,7 @@
"next-themes": "^0.4.6",
"react": "^19.1.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.62.0",
"react-icons": "^5.5.0",
"resend": "^4.7.0",
"tailwind-merge": "^3.3.1",