From f19b7be51a2d540c9ba85fa044d6afbb3361395b Mon Sep 17 00:00:00 2001 From: okxint Date: Tue, 27 Oct 2026 10:23:50 +0530 Subject: [PATCH] fix(form-core): mark unrendered fields as touched on submit The loop in _handleSubmit that marks every field as isTouched was bailing out early when field.instance was null, so fields that were registered but not currently rendered (e.g. in a virtualized list) never had their touch state updated. Switch to Object.entries so we have the field name available, and for fields with no live instance fall through to setFieldMeta directly on the store. Rendered fields continue to go through field.instance.setMeta as before. Fixes #2299 --- ...fix-unrendered-fields-touched-on-submit.md | 5 ++++ packages/form-core/src/FormApi.ts | 28 ++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 .changeset/fix-unrendered-fields-touched-on-submit.md diff --git a/.changeset/fix-unrendered-fields-touched-on-submit.md b/.changeset/fix-unrendered-fields-touched-on-submit.md new file mode 100644 index 0000000000..1416e48a1e --- /dev/null +++ b/.changeset/fix-unrendered-fields-touched-on-submit.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +Mark unrendered fields as touched when the form is submitted diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 4400017d30..7d1d944df3 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -2428,16 +2428,30 @@ export class FormApi< })) batch(() => { - void (Object.values(this.fieldInfo) as FieldInfo[]).forEach( - (field) => { - if (!field.instance) return - // If any fields are not touched + void ( + Object.entries(this.fieldInfo) as [ + DeepKeys, + FieldInfo, + ][] + ).forEach(([fieldName, field]) => { + if (field.instance) { + // Rendered field: update through the live instance if (!field.instance.store.state.meta.isTouched) { - // Mark them as touched field.instance.setMeta((prev) => ({ ...prev, isTouched: true })) } - }, - ) + } else { + // Unrendered field (e.g. virtualized): update the store directly so + // that any validation triggered by the submission attempt can still + // surface errors on these fields when they are next rendered. + const meta = this.getFieldMeta(fieldName) ?? defaultFieldMeta + if (!meta.isTouched) { + this.setFieldMeta(fieldName, (prev = defaultFieldMeta) => ({ + ...prev, + isTouched: true, + })) + } + } + }) }) const submitMetaArg =