T
TanStack7d ago
fascinating-indigo

RHF's onTouched mode

Is it possible to mimic the behavior of React Hook Form's onTouched mode? There doesn't appear to be an equivalent option for validators. https://www.react-hook-form.com/api/useform/#mode
useForm
Performant, flexible and extensible forms with easy-to-use validation.
10 Replies
passive-yellow
passive-yellow7d ago
are you using field-level validators or form-level validators? the easiest way to mimic this is to use a form-level onChange validator, and only show errors in fields if isBlurred: true
fascinating-indigo
fascinating-indigoOP7d ago
form-level validators
passive-yellow
passive-yellow7d ago
isBlurred is currently a one-way change, it won't be set to false if the field isfocused
const form = useForm({
// ...
validators: {
onChange: // ...
}
})

<form.Field name="foo">
{field => <>
{/* ... */}
{field.state.meta.isBlurred && !field.state.meta.isValid && (
<>{/* Display field.state.meta.errors */}</>
)}
</>}
</form.Field>
const form = useForm({
// ...
validators: {
onChange: // ...
}
})

<form.Field name="foo">
{field => <>
{/* ... */}
{field.state.meta.isBlurred && !field.state.meta.isValid && (
<>{/* Display field.state.meta.errors */}</>
)}
</>}
</form.Field>
fascinating-indigo
fascinating-indigoOP7d ago
Your example is very similar to what I have atm. The only thing missing behavior-wise is: when you focus on a field, make no changes, then focus out. No error message appears, because no validations have ran due to no change event. Where as with RHF's onTouched mode, the error would appear, because validations are initially triggered on the first blur event. After that, it switches to being triggered on every change event.
passive-yellow
passive-yellow7d ago
I see. This behaviour should only happen on the initial blur before changes have happened, right?
fascinating-indigo
fascinating-indigoOP7d ago
That's correct
passive-yellow
passive-yellow7d ago
I suppose this may warrant another validateLogic implementation. We currently have one emulating revalidateMode, but that would be bound to submit, not to first vs. rest. I'll see if there's good ways to implement that sometime. In the meantime, this will work well enough to avoid duplicate errors (from having onBlur validators as well as onChange)
listeners: {
onBlur: ({ formApi }) => {
// The form hasn't been interacted with yet.
// note that this is not the same as RHF's !isDirty.
// See https://tanstack.com/form/latest/docs/framework/react/guides/basic-concepts#understanding-isdirty-in-different-libraries
if (formApi.state.isPristine) {
// trigger the change validator
formApi.validate('change')
}
}
}
listeners: {
onBlur: ({ formApi }) => {
// The form hasn't been interacted with yet.
// note that this is not the same as RHF's !isDirty.
// See https://tanstack.com/form/latest/docs/framework/react/guides/basic-concepts#understanding-isdirty-in-different-libraries
if (formApi.state.isPristine) {
// trigger the change validator
formApi.validate('change')
}
}
}
fascinating-indigo
fascinating-indigoOP7d ago
It works great! Thank you so much 🙏 And it would be great to expand revalidateLogic to stuff outside of first-submit, like in this use case.
passive-yellow
passive-yellow7d ago
oh, oops. Yes, formApi.state.isPristine is the correct one I think the use case can be boiled down to:
validationLogic: multipleEvents(['change', 'blur']),
validators: {
onDynamic: // ...
}
validationLogic: multipleEvents(['change', 'blur']),
validators: {
onDynamic: // ...
}
or do you need to differentiate between events and this is the one edge case where it should be triggered?
fascinating-indigo
fascinating-indigoOP7d ago
A way to do onTouched is just the one use case that I needed. I personally don't need anything more custom than what tanstack-form already allows me to very easily. But I do think that the onTouched behavior is a common enough use case in the world form management that it would be great if it was documented on tanstack.com

Did you find this page helpful?