From 81c50db9136820c7981302cc2fa398cf781303c2 Mon Sep 17 00:00:00 2001 From: MarkXian Date: Tue, 14 Jul 2026 20:41:41 +0800 Subject: [PATCH 1/2] fix(form-core): create complete field meta on setFieldValue for uninitialized fields When `setFieldValue` targets a field that has not been mounted yet (e.g. a conditionally rendered field pre-populated before render), the meta updater spread an `undefined` previous meta, producing a partial object missing required fields such as `isValidating`, `isBlurred` and `errorSourceMap`. Default the previous meta to `defaultFieldMeta` so the newly created meta is structurally complete and consistent with a normally mounted field, matching the pattern already used by other `setFieldMeta` call sites. Closes #1078 --- packages/form-core/src/FormApi.ts | 5 ++--- packages/form-core/tests/FormApi.spec.ts | 27 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index d710cd105..cc5bed9be 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -2659,13 +2659,12 @@ export class FormApi< batch(() => { if (!dontUpdateMeta) { - this.setFieldMeta(field, (prev) => ({ + this.setFieldMeta(field, (prev = defaultFieldMeta) => ({ ...prev, isTouched: true, isDirty: true, errorMap: { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - ...prev?.errorMap, + ...prev.errorMap, onMount: undefined, }, })) diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index 024b319f0..b370fb31b 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -83,6 +83,33 @@ describe('form api', () => { }) }) + it('should create complete meta when setFieldValue targets an uninitialized field', () => { + const form = new FormApi({ + defaultValues: { + availableFor: 'longStay', + } as { availableFor: string; fees?: number }, + }) + form.mount() + + // `fees` is rendered conditionally and has not been mounted yet, so its + // meta is created for the first time by this call. + form.setFieldValue('fees', 1) + + const meta = form.getFieldMeta('fees') + + // Every documented meta field must be present (not `undefined`), matching + // the meta of a field that has been mounted normally. + expect(meta).toMatchObject({ + isValidating: false, + isBlurred: false, + errors: [], + errorSourceMap: {}, + }) + expect(meta?.isValidating).not.toBeUndefined() + expect(meta?.isBlurred).not.toBeUndefined() + expect(meta?.errorSourceMap).not.toBeUndefined() + }) + it('should reset with provided custom default values', () => { const defaultValues = { name: 'test', From 51d41039231a282ae8ecd9620052fc359695c628 Mon Sep 17 00:00:00 2001 From: MarkXian Date: Wed, 15 Jul 2026 15:01:50 +0800 Subject: [PATCH 2/2] test(form-core): assert touched and dirty state for meta created by setFieldValue --- packages/form-core/tests/FormApi.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index b370fb31b..802801e7f 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -102,6 +102,9 @@ describe('form api', () => { expect(meta).toMatchObject({ isValidating: false, isBlurred: false, + // `setFieldValue` marks the newly created meta as touched and dirty. + isTouched: true, + isDirty: true, errors: [], errorSourceMap: {}, })