react-hook-form: ReValidateMode 'onChange' doesn't validate after changes?

Describe the bug Not sure if this is a bug or just a misunderstanding on what reValidateMode does…

If I set mode to onBlur and reValidateMode to onChange I expect the value of an input to be validated for the first time when a blur happens on the input (mode).

Assuming the value is not valid, it is in error state at this point. Now, if I change the value of the input to something that is valid, as soon as the value is valid, I would expect the validation to be triggered again, showing no error anymore, as reValidateMode is set to onChange.

If reValidateMode is set to onBlur as well, I would expect it to only validate again when I blur the field after changing the value to a valid one, showing no errors anymore.

The documentation states:

This option allows you to configure when inputs with errors get re-validated after submit. By default, validation is only triggered during an input change.

The description is a bit confusing, as it mentions re-validated after submit, but this doesn’t make sense, as when I set reValidateMode to onChange there is no submit?

To Reproduce Steps to reproduce the behavior:

  1. Open Codesandbox with mode: "onBlur" and reValidateMode: "onChange"
  2. Click on placeholder lastName inside of text field
  3. Type in text Test Name
  4. Click anywhere on the blue background (to blur the text field)
  5. lastName error appears
  6. Click inside of the lastName text field on the right of Test Name (so that the caret is at the end of the text)
  7. Press the backspace key until Name is not there anymore (resulting in Test with space at the end being the value of the text field)

Codesandbox link https://codesandbox.io/s/react-hook-form-useform-template-t597v?file=/src/index.js

Expected behavior At this point, I would expect the error lastName error to disappear, since the lastName text field is now valid (Test contains 5 characters, limit is 5) and an onChange event happened (from pressing the backspace key the last time).

Actual behavior The error lastName error is still present and only disappears when clicking anywhere on the blue background to blur the text field. I would only expect this to happen if reValidateMode was set to onBlur as well.

Desktop (please complete the following information):

  • OS: macOS
  • Browser: Chrome
  • Version 83

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 11
  • Comments: 26 (14 by maintainers)

Most upvoted comments

@bluebill1049 That’s brilliant. Turned out it’s pretty easy (and rather clean!) to make the workaround I need to satisfy my UX requirements. I have to set both mode and reValidateMode to 'onBlur' though, and then trigger the validation manually onChange only if the control is invalid (has any errors).

I’ll simply leave my CSB here just in case future readers might find it useful: https://codesandbox.io/s/react-hook-form-v6-triggervalidation-forked-cbfvt?file=/src/index.js

Thanks again, Bill!! 😃

I’m glad that I came across this issue one month later 'cause actually I want to implement a UX in exactly the same line of theorem as @martinfrancois 🙂

— ✂️ snip ------ There are a couple rules of thumb that guide how we implement validation triggers:

  1. Do not eagerly scold users for invalid data
  • A field should not be changed into an invalid state while the user is interacting with the field
  • This often means holding back on presenting updated validation results until focus leaves the field (onBlur)
  1. Eagerly reward users for correcting invalid data
  • The user should be informed as soon as a field is changed from invalid to valid state
  • This often means presenting updated validation results as soon as the validation state changes from invalid to valid, including on keypress (onChange)

On the surface, these rules can seem slightly contradictory. Do not validate until blur, but validate on change? However, there is a subtlety involved based on the current field validation status. If the field is already invalid, then we should update the validation results on change, without waiting for focus to leave. But if the field is was previously valid or it hasn’t yet been validated, then we should wait until focus leaves the field before updating the validation results for the field. This approach improves usability and decreases frustration for the user. — ✂️ snap ------

It’s so unfortunate that RFH would need a breaking change if this “ideal” behaviour were to be introduced. 😕 But thank you so much @bluebill1049 for such a amazing masterpiece, and for suggesting this workaround:

however, RHF is flexible, you can set both mode to onSubmit and trigger validation accordingly, or simply always trigger the errors and use form state to filter when to display errors

I will try to follow this suggestion and will come back again if I have any questions ✨😁

Ahhh I see… So if reValidateMode kind of changes the mode to be equal to what is set to reValidateMode (temporarily) after the first time the form was submitted?

On another note in this case, would it be possible somehow to configure a behavior like this? So that the field would be validated onBlur first, and after the error appeared on the field it will be validated onChange? I see this as kind of a usability best practice, as when mode was onChange in the first place, it would be confusing for the user, as for example in the case of an email field, as soon as they start typing the first letter it would already tell them the email they entered is invalid, prompting them to think they did something wrong, while they just didn’t finish typing yet. After the user blurs the field, they “confirm” that they are done, and then it shows the error. If the user now refocuses the field to make the change (let’s say they have two @ instead of one) and remove the second @ they should get immediate feedback by removing the error, showing them the input is now valid. It would be annoying if a user had to first blur the text field again to see if it’s correct afterwards, especially since the error is still visible before they blurred the field causing them to believe there is still something wrong. I see a lot of sites who have forms that implement a behavior like this.

Concerning adapting the docs to be more self-explanatory, maybe we could change the doc to say something along the lines of:

`mode` defines WHEN to validate the fields UNTIL the form has been submitted for the first time.
AFTER the form has been submitted for the first time, `reValidateMode` defines WHEN the fields with errors should be validated again.

One thing I could see would be either changing the behavior to apply reValidateMode after the first time there is an error in general (not only after submitting). For me, this feels more logical, as with mode you define when the first validation happens, and reValidationMode (just from the terms) would mean for me when the input should get re-validated after an error (in general). By making this change, this would lead in the same behavior as it was before when mode as onSubmit is used. For others of course, it would be different, which would imply a breaking change. I’m just trying to think of cases for example where one would want to have mode as something else than onSubmit which then would want to change reValidateMode with the current behavior, I can’t think of any use case that would make sense, but I may be missing something.

Thanks for your detailed feedback in terms of when to trigger validation. I don’t think we will make any change to the validation behavior as this is most likely lead to a breaking change. however, RHF is flexible, you can set both mode to onSubmit and trigger validation accordingly, or simply always trigger the errors and use form state to filter when to display errors. in terms of doc improvement please send a PR, we are happy to review and update it.

@bluebill1049 Hi again, Bill. Thank you so much for the new onTouched mode, it’s awesome and is enough to get me going. Unfortunately after I’ve tested the interactions in CSB (https://codesandbox.io/s/react-hook-form-get-started-forked-ilrdu?file=/src/index.js), it still does not quite satisfy my UX requirements.

Here is what I did: 1. Enter “foo” in ExampleRequired control.

2. Delete “foo” from the control. ➡️ no validation result presented. ✅

3. Blur the control. Validation result “This field is required” appears. ➡️ cool, it’s holding back on presenting updated validation results until focus leaves the field (onBlur) when the validation state goes from valid to invalid. 🙂

4. Focus again on the ExampleRequired control and enter “x”. Validation result “This field is required” gone. ➡️ great, it’s presenting updated validation results as soon as the validation state changes from invalid to valid on keypress (onChange). 🙂

5. Delete “x” from the control. Validation result “This field is required” appears. ➡️ here, I expect the validation result should appear only after I blur the control again since the validation state goes from valid to invalid. ❌🙁

Any thoughts of workaround? Should I make use of previous state vs. current state to control when to show the validation result?

I think for your use case (unique), it’s better to build your validation logic with trigger in terms of when validation should be trigger and set both mode and reValidateMode to ‘onSumbit’.

I will release a minor version soon, need to update the changelog and docs.

And yes I read it, I’m just not sure if maybe the docs are not clear enough or I just misunderstood them.

@bluebill1049 sorry, you may be right, I could have forgotten to save the CSB, it should be correct now: https://codesandbox.io/s/react-hook-form-useform-template-t597v?file=/src/index.js