How to enable revalidation on change after calling trigger() in multi-step form? #13248
Replies: 3 comments
why this happensthis is actually a well-known gap in how when rhf decides whether to revalidate a field on change, it checks // simplified from rhf source
if (isSubmitted) {
// use reValidateMode (default: onChange) -> revalidates on change
} else {
// use mode (default: onSubmit) -> only validates on submit
}the key: this has been discussed multiple times in the rhf community with no native fix yet. solutionsthere are a few approaches, ranging from simple config changes to more flexible patterns. option 1: use
|
| approach | pros | cons |
|---|---|---|
mode: 'onTouched' |
simple, good ux | errors show on first blur, not on "next" click |
handleSubmit() per step |
proper lifecycle, revalidation works natively | validates all registered fields, not just current step |
watch + trigger loop |
full control, works with partial fields | more code, extra re-renders from watch |
mode: 'onChange' / 'all' |
zero config | aggressive validation, performance cost |
for most multi-step forms, i'd go with option 2 (handleSubmit per step) since it works with rhf's design rather than against it. if you need to validate only specific fields per step, option 3 gives you the most control.
relevant docs
- useForm
mode-- validation strategy config - trigger() -- manual validation api
- formState --
isSubmittedand related flags - advanced usage: wizard/funnel -- official multi-step patterns
|
If you want “after the first Next click, keep revalidating this step on change”, I’d usually model that explicitly: const stepFields = ['firstName', 'email'] as const
const watchedStepValues = useWatch({ control, name: stepFields })
const [stepAttempted, setStepAttempted] = useState(false)
useEffect(() => {
if (!stepAttempted) return
void trigger(stepFields)
}, [stepAttempted, watchedStepValues, trigger])
const handleNext = async () => {
const ok = await trigger(stepFields)
setStepAttempted(true)
if (ok) {
setStepAttempted(false)
setCurrentStep(2)
}
}That keeps validation scoped to the current step instead of switching the whole form to If you want the simplest UX, |
|
When you manually call However, calling To achieve the behavior where fields continue revalidating on change once they have been validated/triggered, you can use one of the following approaches: 1. Conditional Revalidation via
|
|
The root cause: Quick fix set
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I have a multi-step form, when users click "Next", I validate current step fields using
trigger():Problem: After trigger() validates fields, they don't revalidate on subsequent changes. If a user fixes an invalid field, the error persists until they click "Next" again.
Expected: After trigger() runs, those fields should continue revalidating on change like
onSubmitIs there a way to make trigger() "activate" ongoing validation for specific fields?
All reactions