Forms with React Hook Form and Zod
First, we need to install the necessary dependencies:
yarn add react-hook-form @hookform/resolvers zodyarn add react-hook-form @hookform/resolvers zodNow, we import them:
import { zodResolver } from '@hookform/resolvers/zod'
import { SubmitHandler, useForm } from 'react-hook-form'
import { z } from 'zod'import { zodResolver } from '@hookform/resolvers/zod'
import { SubmitHandler, useForm } from 'react-hook-form'
import { z } from 'zod'We use z.object()z.object() to create a new schema. The schema contains the fields that make up our form.
const formSchema = z
.object({
name: z.string().min(1, 'Name is required').max(100),
email: z.string().min(1, 'Email is required').email('Invalid email'),
password: z
.string()
.min(1, 'Password is required')
.min(8, 'Password must have at least 8 characters'),
confirmPassword: z.string().min(1, 'Password confirmation is required'),
terms: z.literal(true, {
errorMap: () => ({ message: 'You must accept the terms and conditions' }),
}),
})const formSchema = z
.object({
name: z.string().min(1, 'Name is required').max(100),
email: z.string().min(1, 'Email is required').email('Invalid email'),
password: z
.string()
.min(1, 'Password is required')
.min(8, 'Password must have at least 8 characters'),
confirmPassword: z.string().min(1, 'Password confirmation is required'),
terms: z.literal(true, {
errorMap: () => ({ message: 'You must accept the terms and conditions' }),
}),
})To validate password confirmation, we use the refine()refine() method, which accepts two parameters: a callback and an object.
const formSchema = z
.object({
// Rest of the code
...
}).refine((data) => data.password === data.confirmPassword, {
path: ['confirmPassword'],
message: 'Passwords do not match',
})const formSchema = z
.object({
// Rest of the code
...
}).refine((data) => data.password === data.confirmPassword, {
path: ['confirmPassword'],
message: 'Passwords do not match',
})We use z.inferz.infer to extract the form’s type:
type FormSchemaType = z.infer<typeof formSchema>type FormSchemaType = z.infer<typeof formSchema>Finally, inside the form component, we implement React Hook Form passing zodResolver()zodResolver() to resolverresolver. zodResolver()zodResolver() receives the previously created schema as a parameter.
export const Form = () => {
const {
register,
handleSubmit,
reset,
formState: { errors, isSubmitting },
} = useForm<FormSchemaType>({
// Making use of zodResolver
resolver: zodResolver(formSchema),
})
const onSubmit: SubmitHandler<FormSchemaType> = async (data) => {
console.log(data)
}
// Form using React Hook Form
return (
<form onSubmit={handleSubmit(onSubmit)}>
...
</form>
)
}export const Form = () => {
const {
register,
handleSubmit,
reset,
formState: { errors, isSubmitting },
} = useForm<FormSchemaType>({
// Making use of zodResolver
resolver: zodResolver(formSchema),
})
const onSubmit: SubmitHandler<FormSchemaType> = async (data) => {
console.log(data)
}
// Form using React Hook Form
return (
<form onSubmit={handleSubmit(onSubmit)}>
...
</form>
)
}