import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; const signUpSchema = z .object({ email: z .string() .nonempty("email is required") .email("Invalid email address"), password: z.string().min(8, "Password must be at least 8 characters"), confirmPassword: z.string(), }) // we can use zod to validate using refine method .refine((data) => data.password === data.confirmPassword, { message: "Passwords do not match", path: ["confirmPassword"], // it will show error in confirmPassword field }); type ISignUpSchema = z.infer<typeof signUpSchema>; // create type from schema const ReactHookFormWithZod = () => { const [show, setShow] = useState(false); const [show1, setShow1] = useState(false); const { register, handleSubmit, formState, reset } = useForm<ISignUpSchema>({ resolver: zodResolver(signUpSchema), //tell which schema to resolve }); const { errors, isSubmitting } = formState; const onSubmit = async (data: ISignUpSchema) => { console.log(data); //-------send data to server----------// await new Promise((resolve) => setTimeout(resolve, 1000)); //------ reset(); // clear form }; return ( <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-y-4 [&>div>input]:w-full" > <label className="-mb-3 text-sm text-gray-500" htmlFor="email"> email </label> <div className=""> <input {...register("email")} type="text" placeholder="email" className="rounded border px-4 py-2" /> { // granular show errors errors.email && ( <p className="text-sm text-red-500">{`${errors.email.message}`}</p> ) } </div> <label className="-mb-3 text-sm text-gray-500" htmlFor="password"> password </label> <div className="relative "> <input {...register("password")} type={show ? "text" : "password"} id="password" placeholder="password" className=" block rounded border py-2 pl-2 pr-12" ></input> <p className="absolute right-2 top-0 block cursor-pointer select-none py-2 " onClick={() => setShow((show) => !show)} > 👁️ </p> { // granular show errors errors.password && ( <p className="text-sm text-red-500">{`${errors.password.message}`}</p> ) } </div> <label className="-mb-3 text-sm text-gray-500" htmlFor="confirmPassword "> confirm password </label> <div className="relative"> <input {...register("confirmPassword")} id="confirmPassword" type={show1 ? "text" : "password"} placeholder="confirm password" className="rounded border py-2 pl-2 pr-10 " /> <p className="absolute right-2 top-0 block cursor-pointer select-none py-2 " onClick={() => setShow1((show) => !show)} > 👁️ </p> { // granular show errors errors.confirmPassword && ( <p className="text-sm text-red-500">{`${errors.confirmPassword.message}`}</p> ) } </div> <button type="submit" className="rounded bg-blue-500 py-2 text-white disabled:cursor-no-drop disabled:bg-gray-500" disabled={isSubmitting} > {isSubmitting ? "loading..." : "Submit"} </button> </form> ); }; export default ReactHookFormWithZod;
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter