I am trying to display an error with yup
and react-hook-form
when the user selects more than 5 checkboxes without success.
Instead, the error is shown when the seventh checkbox is selected.
Here is the simplified code:
imports...
const schema = yup.object().shape({
option: yup.array().max(5)
});
function App() {
const { register, handleSubmit, errors } = useForm({
mode: "onBlur",
resolver: yupResolver(schema)
});
const [state, setState] = useState({
wasSubmitted: false
});
const submit = async (data) => {
window.alert(JSON.stringify(data));
};
if (state.wasSubmitted) {
return <p>Congrats</p>;
} else {
return (
<>
<CssBaseline />
<Container maxWidth="sm">
<Typography variant="h2" component="h1">
My form
</Typography>
<form noValidate autoComplete="off" onSubmit={handleSubmit(submit)}>
<FormControl
component="fieldset"
error={!!errors.option}
>
<FormLabel component="legend">
Please select the category or categories of books the child is
interested in:
</FormLabel>
<FormGroup>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option1"
label="Option 1"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option2"
label="Option 2"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
label="Option3"
value="Option 3"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option4"
label="Option 4"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option5"
label="Option 5"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option6"
label="Option 6"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option7"
label="Option 7"
/>
<FormControlLabel
control={<Checkbox name="option" inputRef={register} />}
value="Option8"
label="Option 8"
/>
<FormControlLabel
<FormHelperText>Up to five categories</FormHelperText>
</FormControl>
<Button
type="submit"
disableElevation
>
Submit
</Button>
</form>
</Container>
</>
);
}
}
export default App;
You can also find the project's sandbox here:
Any ideas?
Onblur is used when you want to check each element (ie: text, textarea boxes ) individually, and ask the user to correct the input before moving on to the next box. The other event, onsubmit, validates the form at the end, as the user presses the submit button.
onBlur triggers when focus is lost from the input element in context. In React. js, we bind event handlers by passing a method defined in the component to be called accordingly. .bind(this) is called in order to retain the value of this and expose component methods within the event handler function such as this.
React Hook Form is focusing on uncontrolled inputs, which means you don't need to change the input value via state via onChange . This means you don't need value at all, and in fact, you only need to set defaultValue for the initial input value. import { useForm } from 'react-hook-form/dist/index.
FormProvider Performance React Hook Form's FormProvider is built upon React's Context API. It solves the problem where data is passed through the component tree without having to pass props down manually at every level.
Validation will trigger on the first blur event. After that, it will trigger on every change event. Note: when using with Controller, make sure to wire up onBlur with the render prop. Validation will trigger on the blur and change events.
In your code, the form mode is onBlur. it means the validation is triggered on blur event (unfocus the input). When you select the option n+1, it triggers the blur event from the option n. e.g.
Note that React Hook Form only works in Functional Components, not in Class Components. You can check out my video on Let's add Validation in Forms using React and React Hook Form, which is on my YouTube channel.
Warning: this often comes with a significant impact on performance. Validation will trigger on the first blur event. After that, it will trigger on every change event. Note: when using with Controller, make sure to wire up onBlur with the render prop. Validation will trigger on the blur and change events.
As @aadlc said, the solution is to set the mode to onChange
or all
. I'll explain the reason why.
From react-hook-form API docs:
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
Name | Type | Description |
---|---|---|
onSubmit (Default) | string | Validation will trigger on the submit event and invalid inputs will attach onChange event listeners to re-validate them. |
onBlur | string | Validation will trigger on the blur event. |
onChange | string | Validation will trigger on the change event with each input, and lead to multiple re-renders. Warning: this often comes with a significant impact on performance. |
onTouched | string | Validation will trigger on the first blur event. After that, it will trigger on every change event. |
all | string | Validation will trigger on the blur and change events. |
In your code, the form mode is onBlur
. it means the validation is triggered on blur
event (unfocus the input). When you select the option n+1
, it triggers the blur event from the option n
.
e.g. Just before you select the 6th option (invalid), the blur
event fires from the 5th option (valid) because you're no longer focusing it, and validate from option 1-5, so you have to check the 7th option to revalidate the option from 1 to 6.
-- select up to 5 options --
select option 4
blur event fires from option 4 -> validate -> pass
select option 5
blur event fires from option 5 -> validate -> pass
select option 6
blur event fires from option 6 -> validate -> fail
select option 7
Changing the valiation mode to onChange
will validate after change
event is triggered, when all of the values are up-to-date:
-- select up to 5 options --
select option 4
blur event fires from option 4
select option 5
change event fires from option 5 -> validate -> pass
blur event fires from option 5
select option 6
change event fires from option 6 -> validate -> fail
blur event fires from option 6
select option 7
change event fires from option 7 -> validate -> fail
Changing the valiation mode to all
will validate both in blur
and change
events, which may be overkill in this workflow, but it also works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With