From 8e1f6436126bf745a01468462015d873c1e619fc Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Tue, 5 Aug 2025 20:19:11 +0200 Subject: [PATCH] Add basic multi-step form --- app/register_test/page.tsx | 23 +++++++++ components/MultiStepForm.tsx | 97 ++++++++++++++++++++++++++++++++++++ package-lock.json | 16 ++++++ package.json | 1 + 4 files changed, 137 insertions(+) create mode 100644 app/register_test/page.tsx create mode 100644 components/MultiStepForm.tsx diff --git a/app/register_test/page.tsx b/app/register_test/page.tsx new file mode 100644 index 00000000..84626542 --- /dev/null +++ b/app/register_test/page.tsx @@ -0,0 +1,23 @@ +"use client"; + +import {Suspense} from "react"; +import MultiStepForm from "@/components/MultiStepForm"; + + +export default function RegisterPage() { + return ( + }> + + + ); +} + +function RegisterComponent() { + + + return ( +
+ +
+ ); +} diff --git a/components/MultiStepForm.tsx b/components/MultiStepForm.tsx new file mode 100644 index 00000000..4be4707d --- /dev/null +++ b/components/MultiStepForm.tsx @@ -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(); + const isLastStep = step === questions.length - 1; + + const onSubmit: SubmitHandler = (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 ( +
+
+ + {currentQuestion.type === "select" ? ( + + ) : ( + + )} + {errors[currentQuestion.name] && This field is required} +
+
+ {step > 0 && ( + + )} + {!isLastStep ? ( + + ) : ( + + )} +
+
+ ); +}; + +export default MultiStepForm; + diff --git a/package-lock.json b/package-lock.json index 84dcdedd..b7a0150f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 807beecb..8f2b5de7 100644 --- a/package.json +++ b/package.json @@ -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",