Photo by Kelly Sikkema on Unsplash
Notes 01 - React Hook Form + Zod
Just some code snippets & links for my future self. Not a tutorial
Live demo link ( if the link is broken, you can always check the code below )
TL;DR
we need
zodResolver
to integrate react-hook-form with Zod. If you are using other validation library, check the documentation here.refine
comes in handy when you want to use custom validation logic. It takes 2 arguments: validation function and options. See zod documentationwe can set a custom error message in
{message: ‘custom_message‘}
register
method allow you to register an input and apply validation rules.the field errors
errors
is insideformState
which is an object contains info about your entire form state.
Example:
A form with username, email, password and confirm password.
The goal here is to check if
username is valid ( using
regex
to check if the username contains any spaces )email address is valid
the confirm passwords match with passwords ( using
refine
)If there are any validation errors, React Hook Form will prevent form submission.
import React from 'react';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
// define zod schema
const schema = z
.object({
username: z.string()
.trim()
.min(5,{message:"must contain at least 5 characters"})
.regex(/^\S+$/, 'No spaces allowed'),
email: z.string().email({ message: 'Please enter a valid email address' }),
password: z.string().min(8),
confirmPassword: z.string().min(8),
})
.refine(values => values.password === values.confirmPassword, {
message: 'password not match',
path: ['confirmPassword'],
});
function MyForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
defaultValues: {
username: '',
email: '',
password: '',
confirmPassword: '',
},
});
console.log(errors,'errors')
return (
<form
onSubmit={handleSubmit(data => {
console.log(data, 'what is data on submit');
// some api calls here
})}
>
<label >User Name:</label>
<input type="text" {...register('username')} />
{errors.username && <p>{errors.username.message}</p>}
<label>Email:</label>
<input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
<label>Password:</label>
<input type='password' {...register('password')} />
{errors.password && <p>{errors.password.message}</p>}
<label>Confirm Password:</label>
<input type='password' {...register('confirmPassword')} />
{errors.confirmPassword && <p>{errors.confirmPassword.message}</p>}
<button type='submit'>Submit</button>
</form>
);
}
export default MyForm;
CSS code
.App {
color: #81e391;
}
form {
max-width: 700px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input {
outline:none;
width:100%;
padding:10px 0;
border-radius: 3px;
border: 1px solid #ccc;
margin-bottom:10px;
}
button {
display: block;
margin: 10px 0;
padding: 10px 20px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
p{
color:rgb(233, 107, 107);
margin:0;
}