Skip to content

fix: ensure fieldName is passed to custom validation logic functions#2127

Merged
harry-whorlow merged 3 commits intoTanStack:mainfrom
mwg-ofx:dynamic-validation-fieldname
Apr 21, 2026
Merged

fix: ensure fieldName is passed to custom validation logic functions#2127
harry-whorlow merged 3 commits intoTanStack:mainfrom
mwg-ofx:dynamic-validation-fieldname

Conversation

@mwg-ofx
Copy link
Copy Markdown
Contributor

@mwg-ofx mwg-ofx commented Apr 16, 2026

🎯 Changes

This was always part of the types for custom validation functions (see #1622), it just wasn't wired up. This update is pretty straightforward - it just wires up the field, and adds a test to prove that custom field-level dynamic validation is now possible. The example in the test mostly follows a basic version of what's outlined in #1861.

Fixes #1861

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Custom validation logic now receives the relevant field name for all validation events (mount/change/blur/submit), including when evaluating related/linked fields—enabling validators to know which field they apply to.
    • Submit now triggers comprehensive revalidation that can invoke field-level validators multiple times as needed.
  • Tests

    • Added tests covering dynamic field-level validation (sync and async) for blur- and submit-triggered scenarios.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

FieldApi now supplies fieldName when assembling validators; utils forward fieldName into the validationLogic event for sync and async flows; ValidationLogicValidatorsFn is exported; tests added to verify dynamic field-level validation using event.fieldName.

Changes

Cohort / File(s) Summary
Release Metadata
​.changeset/whole-views-wear.md
Added a changeset noting fieldName is passed into custom validation logic functions.
Field API & Validator Assembly
packages/form-core/src/FieldApi.ts
Includes fieldName when building sync/async validator arrays for the current field and when collecting validators from linked fields.
Validation Utilities
packages/form-core/src/utils.ts
getSyncValidatorArray / getAsyncValidatorArray accept optional fieldName; the validationLogic event payload now includes fieldName for both sync and async flows.
Type Export
packages/form-core/src/ValidationLogic.ts
ValidationLogicValidatorsFn interface made exported for external imports.
Tests
packages/form-core/tests/DynamicValidation.spec.ts
Added tests exercising customised field-level validation logic that reads event.fieldName, covering sync and async dynamic validation behaviors.

Sequence Diagram(s)

sequenceDiagram
  participant FieldApi as FieldApi
  participant Utils as getSync/AsyncValidatorArray
  participant ValidationLogic as validationLogic
  participant Validators as ValidatorFns

  FieldApi->>Utils: request validator array (include fieldName)
  Utils->>ValidationLogic: call validationLogic(event { type, async, fieldName })
  ValidationLogic->>Validators: decide/append validators (may use fieldName)
  Validators-->>ValidationLogic: return selected validators
  ValidationLogic-->>Utils: return final validator list
  Utils-->>FieldApi: provide validators / run validation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hopped through code where names were lost,

I nudged fieldName back across the moss,
Now validators know whose field to mind,
Errors shrink as logic learns to find,
A tiny patch — a clearer trail I crossed.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: wiring up fieldName to custom validation logic functions.
Description check ✅ Passed The description covers the key points, follows the template structure, and includes all checked items (contributing guide, local testing, changeset generation).
Linked Issues check ✅ Passed The PR fully addresses issue #1861 by wiring up fieldName to custom validation logic and adding comprehensive tests demonstrating dynamic field-level validation.
Out of Scope Changes check ✅ Passed All changes are directly related to wiring up fieldName in validation logic as required by issue #1861; no out-of-scope modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/form-core/tests/DynamicValidation.spec.ts (1)

238-333: Consider adding one async linked-field case to prevent fieldName regressions.

A small async linked validation scenario asserting props.event.fieldName for the linked field would lock in the async path as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/form-core/tests/DynamicValidation.spec.ts` around lines 238 - 333,
Add an async linked-field scenario to the existing test to cover the async path
that depends on props.event.fieldName: update the validationLogic used in the
spec to include a case where a validator is async and references a linked field
(so props.event.fieldName is set for that linked field) and then exercise that
path by triggering the linked-field event (e.g., blur/change/submit on the
linked field) and awaiting the validation; specifically modify the test that
defines validationLogic, FieldApi instances and their validators ('onDynamic')
to add a linked async validator and assertions that await and assert errorMap
for the linked field to ensure the props.event.fieldName branch is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/form-core/src/FieldApi.ts`:
- Around line 1828-1832: Linked-field async validators are receiving the
triggering field's name (this.name) instead of the linked field's name; update
the linked-field validation loop where getAsyncValidatorArray is called (using
field.options, field.form, validationLogic) to set fieldName to the linked
field's identifier (e.g., linkedField.name or the loop variable representing the
linked field) rather than this.name so event.fieldName in the custom async
validationLogic reflects the linked field.

---

Nitpick comments:
In `@packages/form-core/tests/DynamicValidation.spec.ts`:
- Around line 238-333: Add an async linked-field scenario to the existing test
to cover the async path that depends on props.event.fieldName: update the
validationLogic used in the spec to include a case where a validator is async
and references a linked field (so props.event.fieldName is set for that linked
field) and then exercise that path by triggering the linked-field event (e.g.,
blur/change/submit on the linked field) and awaiting the validation;
specifically modify the test that defines validationLogic, FieldApi instances
and their validators ('onDynamic') to add a linked async validator and
assertions that await and assert errorMap for the linked field to ensure the
props.event.fieldName branch is exercised.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 18dbf798-0f75-4e1b-8636-58dd478bdd92

📥 Commits

Reviewing files that changed from the base of the PR and between 254f157 and ad2cd71.

📒 Files selected for processing (5)
  • .changeset/whole-views-wear.md
  • packages/form-core/src/FieldApi.ts
  • packages/form-core/src/ValidationLogic.ts
  • packages/form-core/src/utils.ts
  • packages/form-core/tests/DynamicValidation.spec.ts

Comment thread packages/form-core/src/FieldApi.ts
This was always part of the types for custom validation functions, it
just wasn't wired up. This update is pretty straightforward - it just
wires up the field, and adds a test to prove that custom field-level
dynamic validation is now possible. The example in the test mostly
follows a basic version of what's outlined in TanStack#1861.

Fixes TanStack#1861
@mwg-ofx mwg-ofx force-pushed the dynamic-validation-fieldname branch from ad2cd71 to 72c0b37 Compare April 16, 2026 03:33
@crutchcorn
Copy link
Copy Markdown
Member

Whoops! My bad for having this bug in the first place! Good catch.

The code generally LGTM at a quick glance, but I want to have another maintainer take a closer look at the tests in particular since I'm deep in Form Group land and just got an email so I thought I'd take a look. I'll have it prioritized given the quality of the PR.

Thanks!

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 16, 2026

View your CI Pipeline Execution ↗ for commit b3a5729

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 34s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-20 20:25:29 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 16, 2026

More templates

@tanstack/angular-form

npm i https://pkg.pr.new/@tanstack/angular-form@2127

@tanstack/form-core

npm i https://pkg.pr.new/@tanstack/form-core@2127

@tanstack/form-devtools

npm i https://pkg.pr.new/@tanstack/form-devtools@2127

@tanstack/lit-form

npm i https://pkg.pr.new/@tanstack/lit-form@2127

@tanstack/react-form

npm i https://pkg.pr.new/@tanstack/react-form@2127

@tanstack/react-form-devtools

npm i https://pkg.pr.new/@tanstack/react-form-devtools@2127

@tanstack/react-form-nextjs

npm i https://pkg.pr.new/@tanstack/react-form-nextjs@2127

@tanstack/react-form-remix

npm i https://pkg.pr.new/@tanstack/react-form-remix@2127

@tanstack/react-form-start

npm i https://pkg.pr.new/@tanstack/react-form-start@2127

@tanstack/solid-form

npm i https://pkg.pr.new/@tanstack/solid-form@2127

@tanstack/solid-form-devtools

npm i https://pkg.pr.new/@tanstack/solid-form-devtools@2127

@tanstack/svelte-form

npm i https://pkg.pr.new/@tanstack/svelte-form@2127

@tanstack/vue-form

npm i https://pkg.pr.new/@tanstack/vue-form@2127

commit: b3a5729

@sentry
Copy link
Copy Markdown

sentry Bot commented Apr 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.25%. Comparing base (6892ed0) to head (b3a5729).
⚠️ Report is 167 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2127      +/-   ##
==========================================
- Coverage   90.35%   90.25%   -0.10%     
==========================================
  Files          38       49      +11     
  Lines        1752     2043     +291     
  Branches      444      532      +88     
==========================================
+ Hits         1583     1844     +261     
- Misses        149      179      +30     
  Partials       20       20              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@harry-whorlow
Copy link
Copy Markdown
Contributor

This pr is pretty solid!

I'm just trying to reason through some stuff, but I want to get this merged by the end of the weekend. 🚀

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/form-core/tests/DynamicValidation.spec.ts (1)

427-502: Restore real timers after this test completes.

The test calls vi.useFakeTimers() on line 428 but never restores them, which can cause test pollution for subsequent tests. Wrap the test body in try/finally and call vi.useRealTimers() in the finally block.

Proposed fix
     it('should support async validation', async () => {
       vi.useFakeTimers()
+      try {
 
       const form = new FormApi({
         defaultValues: {
           firstName: '',
@@
       fieldLastName.handleChange('Smith')
       await vi.runAllTimersAsync()
       expect(fieldLastName.state.meta.errorMap.onDynamic).toBe(undefined)
+      } finally {
+        vi.useRealTimers()
+      }
     })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/form-core/tests/DynamicValidation.spec.ts` around lines 427 - 502,
The test "should support async validation" uses vi.useFakeTimers() but never
restores timers; wrap the test body (the async function passed to it) in a
try/finally and call vi.useRealTimers() in the finally block so timers are
restored even on failure. Locate the test by the it(...) with description
'should support async validation', add a try/finally around its existing logic
and invoke vi.useRealTimers() in the finally to undo vi.useFakeTimers().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/form-core/tests/DynamicValidation.spec.ts`:
- Around line 306-310: The test currently uses
expect.arrayContaining(['one','one',undefined,undefined]) which doesn't assert
exact call counts; update the assertion after await form.handleSubmit() to
explicitly verify that validate was invoked twice for the 'one' field and that
two undefined entries exist (or assert strict array equality of submitTarget to
the expected array). Concretely, replace the arrayContaining check on
submitTarget with assertions that count occurrences of 'one' (expect length 2)
and occurrences of undefined (expect length 2), or assert submitTarget === the
exact expected array; reference submitTarget, form.handleSubmit,
validateAllFields and validate when locating the failing expectation.

---

Nitpick comments:
In `@packages/form-core/tests/DynamicValidation.spec.ts`:
- Around line 427-502: The test "should support async validation" uses
vi.useFakeTimers() but never restores timers; wrap the test body (the async
function passed to it) in a try/finally and call vi.useRealTimers() in the
finally block so timers are restored even on failure. Locate the test by the
it(...) with description 'should support async validation', add a try/finally
around its existing logic and invoke vi.useRealTimers() in the finally to undo
vi.useFakeTimers().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ed0e51ae-7c36-4d25-a980-9be21a21df25

📥 Commits

Reviewing files that changed from the base of the PR and between 58473fe and b3a5729.

📒 Files selected for processing (1)
  • packages/form-core/tests/DynamicValidation.spec.ts

Comment thread packages/form-core/tests/DynamicValidation.spec.ts
@harry-whorlow
Copy link
Copy Markdown
Contributor

LGTM 🚀

@harry-whorlow harry-whorlow merged commit 6b8aa1e into TanStack:main Apr 21, 2026
9 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validation Logic Fn: event.fieldName seems to always be undefined despite existing in props

3 participants