Hidden field doesn't show errors on mount
Describe the bug
I have my form fields in a Popper, meaning my form object mounts before my fields. This leads to the situation where the field level errors are not displayed when the popper opens. There may be a simple solution to this but I've been playing around and haven't found yet. Any help would be appreciated.
Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-8bcuwtpv?file=src%2FApp.tsx
Steps to reproduce
- hit "show field"
- observe no red text below input field
- type and clear out text
- red error will appear
Expected behavior
I expect the red text to appear immediately after clicking show field
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
- macOS
- brave 1.78.97
TanStack Form adapter
None
TanStack Form version
1.14.2
TypeScript version
No response
Additional context
No response
Actually the behavior you're seeing is correct based on how you've configured the form.
You've defined a form-level onMount, but you're expecting field-level onMount behavior.
I've forked your sandbox
Mhm ok. I guess my only concern would be that this could get verbose quickly, for many fields. But I guess I can limit it to those fields that mount after the form and that I know will have an error on mount.
Thanks much!
@kusiewicz one more question: I notice this fix does not work with custom errors defined with zod's .check.
I created a new reproduction: https://stackblitz.com/edit/vitejs-vite-9bzkjdnu?file=src%2FApp.tsx
After you click the 'show' button, the text 'Age must be defined' is missing from the field level error for the age field. This error does exist at the form level, due to the .check I defined.
Any feedback on this one?
Actually I've just run into a similar problem.
So you're logging out onMount form errors - they actually exist immediately - before Show btn is clicked. But its not synced with field errors. When hidden fields are mounted they have empty error fields (field.state.meta.errors).
One way is to display formErrors from formErrorMap - because formState has those errors right away.
https://stackblitz.com/edit/vitejs-vite-n5ak5khm?file=src%2FApp.tsx
But i think its weird since late form validators (e.g onChange) updates field state. I am now wondering whether errors from onMount at the form level should not synchronize the initial errors of fields even if they are not mounted.
@LeCarbonator any thoughts? :)
Okay did some digging in the code and its look like that:
- When
Appis rendereduseFormis called. At this moment library createsforminstance and immediately runsformonMountvalidation. - In the same time when
onMountvalidation is run, ourshowstate has valuefalse. It means that<form.Field>components are not mounted yet.Formtries assign validation errors to particular fields, but those fields does not exists yet at all. - You're clicking
show- state changes totrue. - React mounts
<form.Field>components. Each field is being registered in the form. ButonMountvalidation happened on form level in thestep 1and will not be called again. Fields are mounted with clearmetastate since at the moment of theirs registration,formdoes not have "waiting" errors for them.
When show is true by default - fields mounts at the same moment like the form, so onMount validation founds its targets right away and assigns them errors.
Maybe in cases like that the best way is simply call form.ValidateAllFields() after switching state?
I think the mounted state of fields shouldn't matter if there are errors assigning them. Otherwise, you risk using field-level errors at all.
I'll look into it in a bit!
I think the mounted state of fields shouldn't matter if there are errors assigning them. Otherwise, you risk using field-level errors at all.
I'll look into it in a bit!
I think that regardless of whether the fields are mounted or not, they should always receive their initial errors from the first onMount
I'm running into this exact same issue in my current project, and had to rewrite everything so that fields aren't mounted/unmounted. As a workaround, I'm using the hidden HTML attribute—which doesn't feel great.
Definitely curious to see what the fix will be for this.
@marc-at-brightnight @LeCarbonator
This is obviously less-than-ideal, but hopefully it provides some insights into the issue.
Looking at Marc's Stackblitz, if you add:
function toggleVisibility() {
flushSync(() => {
setShow((v) => !v);
});
form.validate("change");
}
And then apply that to the button:
<button onClick={toggleVisibility}>
{show ? "Hide" : "Show"} Field
</button>
The form behaves as expected...
function toggleVisibility() { flushSync(() => { setShow((v) => !v); }); form.validate("change"); }And then apply that to the button:
<button onClick={toggleVisibility}> {show ? "Hide" : "Show"} Field </button>The form behaves as expected...
Yeah this is what I ended up doing, at least the validate part. I think it's fine as a workaround, validation is pretty fast for my use cases. I'm fine to close this as completed.
I am running into this issue, or something very similar. I may just be confused about how unmounted fields work.
my setup:
I have a field group that's got 2 fields in a popover, so they are only mounted when the popover is open. There's a checkbox (outside the popover) that enables/disables the field.
I have validation on the fields and I'm using onChangeListenTo to include the checkbox in the validation (and bypass it). This all works fine when the popover is open, but when it's closed and I click on the checkbox, only the first validation change is saved to the field's state. If I continue to toggle the checkbox, the validation function runs every (visible in console), but any errors it produces are lost and the field's meta state is still valid.
I modified the example to show this issue: https://stackblitz.com/edit/vitejs-vite-gqyskrvt?file=src%2FApp.tsx
The workaround above doesn't work, the validation function is running everytime as expected, but the result is discarded if the form is unmounted. I would like to show the validation status when the checkbox is toggled, even if the popover is closed.
EDIT:
it seems that if I move the validation to the form level instead of field level, then the errors are saved and displayed properly, so this is one workaround.