Article summary
React Hook Form is a library for smoothly handling forms in React. It’s simpler and more efficient than using react state for form state management. React hook form use hooks to manage input values, validation, and submission. It has built in validation and is easy to integrate with other validation libraries. Here, I will show examples of how to use React Hook Form with Zod validation.
Zod
Zod is a Typescript-first validation library. It can be used to define and enforce validation rules for user input, API responses, and application data structures. It can automatically infer Typescript types from a validation schema. With Zod, you can combine multiple validation rules, define them once, and then use them across frontend and backend using one validation schema.
Application Form Using React Hook Form and Zod Validation
First, I define the validation schema for a job application form, so the form has something to validate against.
import { z } from "zod";
const passwordStrengthSchema = z
.string()
.min(6, "Password must be at least 6 characters")
.regex(/[!@#$%^&*(),.?":{}|<>]/, "Password must include a special character")
.regex(/[A-Z]/, "Password must include an uppercase letter")
.regex(/\d/, "Password must include a number");
export const jobApplicationSchema = z.object({
fullName: z.string().min(3, "Full Name must be at least 3 characters long"),
email: z.string().email("Invalid email format"),
jobRole: z.enum(["frontend", "backend", "fullstack", "designer"], {
message: "Please select a job role",
}),
resume: z
.instanceof(FileList)
.refine((files) => files.length > 0, "Resume is required")
.refine(
(files) => files[0] && files[0].type === "application/pdf",
"Only PDF files are allowed"
),
password: passwordStrengthSchema,
terms: z.literal(true, {
errorMap: () => ({ message: "You must accept the terms and conditions" }),
}),
});
Then, in the form component, I use zodResolver
to enforce the validation schema.
const formMethods = useForm({
defaultValues: initalState, // provides an initial state for rhe form
mode: "onChange",
resolver: zodResolver(jobApplicationSchema)
});
const {
register, // enables tracking and validation
handleSubmit,
watch, // allows observation of form fields
formState: { isSubmitting, isValid },
} = formMethods;
In the example above, I set the mode
to “onChange”. This means validation will run on every keystroke. Other modes that can be used are:
- “onSubmit” – validates only when the user submits the form.
- “onBlur” – validates when the user navigates away from the form field.
- “all” – runs validation on every keystroke and blur event (more performance heavy).
Also, I am using the built-in function watch()
to monitor the value of a specific form field. I will show an example of how to use watch()
to provide real-time feedback to users before the form is submitted.
const watchResume = watch("resume");
return (
<div>
<h1>Job Application Form<</h1>
<form onSubmit={handleSubmit(onSubmit)}>
{/* Resume Upload */}
<div>
<label>Upload Resume (PDF only):</label>
<input type="file" accept="application/pdf" {...register("resume")} />
{/* Show File Name in Real-Time */}
<p>Selected File: {watchResume?.[0]?.name || "No file selected"}</p>
<div>
{/* Submit Button */}
<button type="submit" disabled={!isValid || isSubmitting}>
{isSubmitting ? "Submitting..." : "Submit Application"}
</button>
</form>
<div>
);
In the above example, I define watchResume
. Then I use watchResume?.[0]?.name
to display the filename once it’s selected.
In order to track the form field and apply the validation, I must register each field as such:
<input type="file" accept="application/pdf" {...register("resume")} />
Submitting the Form
In this example, I want to disable the submit button until all fields are valid. I can use the form method isValid to achieve this.
<button type="submit" disabled={!isValid}>
{isSubmitting ? "Submitting..." : "Submit Application"}
</button>
React Hook Form provides the form state isSubmitting and isValid. So if all fields pass the validation, the button will be enabled.
React Hook Form Plus Zod
In conclusion, React Hook Form paired with Zod can simplify form handling and validation. These techniques can save development time and reduce complexity. In part two, we will look at error handling and how to share form state across nested components without prop drilling by using FormProvider and useFormContext.