React Hook Form Cross-field Validation
A cross-field validation rule is where the rule is dependent on multiple fields. This post covers how to implement these types of validation rules in React hook Form.
An example
We have the following form that captures a low and high score:
type Scores = {
low: number;
high: number;
};
const ScoreForm = () => {
const { register, handleSubmit } = useForm<Scores>();
const onSubmit = (data: Scores) => {
console.log("data", data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="field">
<label htmlFor="low">Lowest score</label>
<input type="number" id="low" name="low" ref={register} />
</div>
<div className="field">
<label htmlFor="high">Highest score</label>
<input type="number" id="high" name="high" ref={register} />
</div>
<button type="submit">Save</button>
</form>
);
};
This is a straightforward React Hook Form with no validation rules at the moment.
Adding simple validation
The scores are manditory and we want them to be between 0 and 10. Implementing these rules is super simple:
const ScoreForm = () => {
const {
register,
handleSubmit,
errors } = useForm<Scores>();
...
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="field">
<label htmlFor="low">Lowest score</label>
<input
type="number"
id="low"
name="low"
ref={register({
required: true, min: 0, max: 10 })}
/>
{errors.low && errors.low.type === "required" && ( <div className="error">You must enter a score.</div> )} {errors.low && errors.low.type === "min" && ( <div className="error">The score must be at least 0.</div> )} {errors.low && errors.low.type === "max" && ( <div className="error">The score can't be more than 10.</div> )} </div>
<div className="field">
<label htmlFor="high">Highest score</label>
<input
type="number"
id="high"
name="high"
ref={register({
required: true, min: 0, max: 10 })}
/>
{errors.high && errors.high.type === "required" && ( <div className="error">You must enter a score.</div> )} {errors.high && errors.high.type === "min" && ( <div className="error">The score must be at least 0.</div> )} {errors.high && errors.high.type === "max" && ( <div className="error">The score can't be more than 10.</div> )} </div>
<button type="submit">Save</button>
</form>
);
};
The form fields now capture a low and high score between 0 and 10.
Adding cross-field validation
Can you spot a gap in the validation rules?
Yes, that’s right - the low score can be higher than the high score!
Let’s implement an additional validation rule to check the low score isn’t higher than the high score. This rule is an example of a cross-field validation rule because it is based on multiple fields - it is dependent on both the low and high score fields.
We can implement cross-field validation rules in React Hook Form with a custom validation rule.
First, we need to destructure the getValues
from React Hook Form. This function allows us to access any field value on the form. We’ll need to use this in our custom validator function.
const {
register,
handleSubmit,
errors,
getValues,} = useForm<Scores>();
Now let’s implement the custom validation rule on the high score field:
<input
type="number"
id="high"
name="high"
ref={register({
required: true,
min: 0,
max: 10,
validate: () => Number(getValues("low")) <= Number(getValues("high")) })}
We set the validate
property in the register
function’s object parameter to an inline validator function. A custom validator function for React Hook Form returns true
if it passes and false
if the rule fails. We use the getValues
function to get the relevant field values in the validator function. The values of the fields are strings, so we use the Number
constructor to convert them to numbers before doing the check.
Nice!
Let’s add the validation error message:
<input
type="number"
id="high"
...
/>
...
{errors.high && errors.high.type === "validate" && ( <div className="error"> The highest score can't be less than the lowest score. </div>)}
The type
property for a custom validation rule error is “validate”.
The validation error appears next to an invalid high score field when the form is submitted:
We could add this rule to the low score field as well, but it’s not necessary.
Wrap up
You can use a custom validation rule to implement cross-field validation in React Hook Form. The getValues
function must be used to get access to the field values the rule is dependent on in the validator function.
Did you find this post useful?
Let me know by sharing it on Twitter.If you to learn more about using TypeScript with React, you may find my course useful: