Skip to content

Add preact integration for tanstack form#2043

Open
JoviDeCroock wants to merge 14 commits intoTanStack:mainfrom
JoviDeCroock:preact-integration
Open

Add preact integration for tanstack form#2043
JoviDeCroock wants to merge 14 commits intoTanStack:mainfrom
JoviDeCroock:preact-integration

Conversation

@JoviDeCroock
Copy link
Copy Markdown

@JoviDeCroock JoviDeCroock commented Feb 15, 2026

🎯 Changes

  • Add new @tanstack/preact-form package to the monorepo.
  • Use @tanstack/preact-store instead of @tanstack/react-store.
  • Use useId from preact/hooks for form ID generation.
  • Set preact peer dependency to >10.11.0 for useId support.

Summary by CodeRabbit

  • New Features

    • Official Preact support: new Preact form package with hooks, field components, form composition helpers, and reactive subscriptions.
  • Documentation

    • Extensive Preact docs: Quick Start, Guides (validation, arrays, async init, listeners, reactivity, debugging, focus, composition, UI libs, etc.), and full API reference.
  • Examples

    • Added a runnable Preact example demonstrating common form patterns.
  • Tests

    • Added runtime and type-level tests exercising Preact form APIs.
  • Chores

    • Workspace and build/test config updates for the new Preact package.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 15, 2026

⚠️ No Changeset found

Latest commit: 36749f4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Feb 15, 2026

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 0e39f14

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

☁️ Nx Cloud last updated this comment at 2026-04-01 00:50:09 UTC

Copy link
Copy Markdown
Contributor

@theVedanta theVedanta left a comment

Choose a reason for hiding this comment

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

compat and use-client are the only things I wanna flag, since they're in multiple files. Apart from that, looks okay. The onInput prop isn't important as such, but would be a nice-to-have.

Field: FieldComponent<
TFormData,
TOnMount,
TOnChange,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I feel like fields should have an onInput prop instead of onChange for it to be consistent with Preact. If we can do that, it'd be awesome

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't think anyone would benefit from that, the end-user is still free to use onInput in exchange for onChange at their disposal

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, gotcha. But how would users use onInput in parts of the API that are not the children?

          <form.Field
            name="firstName"
            validators={{
              onInput: ({ value }) =>
                !value
                  ? 'A first name is required'
                  : value.length < 3
                    ? 'First name must be at least 3 characters'
                    : undefined,
            }}
            ...

I can understand if you feel like they don't, I was only thinking about it because of consistency with Preact's naming.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ah I see what you mean now, sorry I didn't derive the validator enforcement from the comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Validators should use onChange even on adapters that use onInput. That comes from core. No need to change :)

Copy link
Copy Markdown
Contributor

@theVedanta theVedanta left a comment

Choose a reason for hiding this comment

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

Once we can finalize this, let's get the docs in place and merge! Super excited to use preact-form 🔥

Field: FieldComponent<
TFormData,
TOnMount,
TOnChange,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, gotcha. But how would users use onInput in parts of the API that are not the children?

          <form.Field
            name="firstName"
            validators={{
              onInput: ({ value }) =>
                !value
                  ? 'A first name is required'
                  : value.length < 3
                    ? 'First name must be at least 3 characters'
                    : undefined,
            }}
            ...

I can understand if you feel like they don't, I was only thinking about it because of consistency with Preact's naming.

@sentry
Copy link
Copy Markdown

sentry bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 95.77465% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (6892ed0) to head (4030ef8).
⚠️ Report is 141 commits behind head on main.

Files with missing lines Patch % Lines
packages/preact-form/src/useForm.tsx 86.48% 4 Missing and 1 partial ⚠️
packages/preact-form/src/createFormHook.tsx 97.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2043      +/-   ##
==========================================
- Coverage   90.35%   90.31%   -0.04%     
==========================================
  Files          38       55      +17     
  Lines        1752     2148     +396     
  Branches      444      522      +78     
==========================================
+ Hits         1583     1940     +357     
- Misses        149      186      +37     
- Partials       20       22       +2     

☔ 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.

@theVedanta
Copy link
Copy Markdown
Contributor

LGTM! @crutchcorn just needs to approve the worflows perhaps?

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 4, 2026

More templates

@tanstack/angular-form

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

@tanstack/form-core

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

@tanstack/form-devtools

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

@tanstack/lit-form

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

@tanstack/preact-form

npm i https://pkg.pr.new/TanStack/form/@tanstack/preact-form@2043

@tanstack/react-form

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

@tanstack/react-form-devtools

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

@tanstack/react-form-nextjs

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

@tanstack/react-form-remix

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

@tanstack/react-form-start

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

@tanstack/solid-form

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

@tanstack/solid-form-devtools

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

@tanstack/svelte-form

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

@tanstack/vue-form

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

commit: 0e39f14

Copy link
Copy Markdown
Member

@crutchcorn crutchcorn left a comment

Choose a reason for hiding this comment

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

Pushed some minor changes to sync with main. Otherwise LGTM. Waiting on @KevinVandy to help us publish before merging (he'll merge for us)

@LeCarbonator
Copy link
Copy Markdown
Contributor

Looks like the lock has some conflicts now

@JoviDeCroock JoviDeCroock deleted the preact-integration branch March 29, 2026 09:56
@JoviDeCroock JoviDeCroock restored the preact-integration branch March 31, 2026 18:40
@JoviDeCroock JoviDeCroock reopened this Mar 31, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

📝 Walkthrough

Walkthrough

Adds first-class Preact support for TanStack Form: a new @tanstack/preact-form package with implementation (hooks, components, utilities), extensive Preact-specific documentation and reference, test suites (runtime + type tests), example app, and build/lint/test configuration files.

Changes

Cohort / File(s) Summary
Docs config & build
docs/config.json, scripts/generate-docs.ts, pnpm-workspace.yaml
Register Preact docs in navigation and add docs generation / workspace globs for the new package and examples.
Preact docs — Quickstart & Guides
docs/framework/preact/quick-start.md, docs/framework/preact/guides/*
New Quick Start and many guides covering basic concepts, arrays, validation, dynamic validation, listeners, reactivity, focus management, form composition, UI library integrations, debugging, async initial values, submission handling, custom errors, and more.
Preact docs — API reference
docs/framework/preact/reference/...
Complete generated API reference pages for functions, interfaces, type aliases, and variables (useForm, useField, useFieldGroup, createFormHook, createFormHookContexts, useStore, ReactFormApi, etc.).
Package manifest & tooling
packages/preact-form/package.json, packages/preact-form/tsconfig*.json, packages/preact-form/vite.config.ts, packages/preact-form/eslint.config.js, packages/preact-form/README.md
New package metadata, TypeScript and docs tsconfigs, Vite/Vitest configuration, ESLint overrides, and package README.
Core implementation: form runtime
packages/preact-form/src/useForm.tsx, packages/preact-form/src/useField.tsx, packages/preact-form/src/useFieldGroup.tsx, packages/preact-form/src/createFormHook.tsx, packages/preact-form/src/useStore.ts, packages/preact-form/src/useIsomorphicLayoutEffect.ts, packages/preact-form/src/useFormId.ts, packages/preact-form/src/index.ts, packages/preact-form/src/types.ts
New Preact adapter implementation: typed hooks, Field/FieldGroup integrations, createFormHook utilities, a bridging useStore, isomorphic layout effect, form-id alias, and exported types/entry points.
Examples
examples/preact/simple/*
Minimal Preact example app (Vite + Preact) with README, entry HTML, index.tsx demo, tsconfig and Vite config.
Tests — runtime
packages/preact-form/tests/*.{test.tsx,ts}
Comprehensive Vitest + Testing Library runtime tests covering useForm, useField, createFormHook, field arrays, validation flows, async/debounce, and composition behaviors.
Tests — type declarations
packages/preact-form/tests/*.{test-d.tsx}
Extensive TypeScript declaration tests validating generics, inference, withForm/withFieldGroup typings, and ensure type stability.
Test utilities & setup
packages/preact-form/tests/test-setup.ts, packages/preact-form/tests/utils.ts
Test setup and small utilities (cleanup, sleep).
Angular docs formatting fixes
various docs/framework/angular/guides/*
Minor formatting/whitespace/semicolon changes in Angular example snippets (no API changes).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App as Preact App
    participant Form as Form API (useForm)
    participant Store as Form Store
    participant Field as Field Component

    User->>App: interact with UI (input / submit)
    App->>Form: create instance via useForm(opts)
    Form->>Store: create & manage state store
    App->>Field: render form.Field (passes form)
    Field->>Store: subscribe to field slice
    User->>Field: type/change input
    Field->>Form: field.handleChange(value)
    Form->>Store: validate/update state
    Store-->>Field: emit updated field state
    App->>Form: form.handleSubmit()
    Form->>Form: run validators and call onSubmit(values)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 nibbles a carrot, then hops delightedly
Preact fields spring up in tidy little rows,
Hooks and validators where the soft wind blows,
Docs and tests stitched snug, an example to show,
A rabbit hops in — “Preact forms, let’s go!”

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete. It lists changes but is missing the required checklist items and does not confirm whether a changeset was generated for the published code changes. Complete the checklist by confirming steps followed in the Contributing guide and testing via 'pnpm test:pr'. Also confirm whether a changeset was generated or if this is docs/CI-only.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add preact integration for tanstack form' clearly summarizes the main change: adding Preact support to TanStack Form with a new package.

✏️ 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: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

♻️ Duplicate comments (3)
docs/framework/preact/reference/type-aliases/UseField.md (2)

12-12: ⚠️ Potential issue | 🔴 Critical

Incorrect source file reference for Preact documentation.

The "Defined in:" link references packages/react-form/src/useField.tsx but this is Preact framework documentation. This should point to packages/preact-form/src/useField.tsx instead.

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

In `@docs/framework/preact/reference/type-aliases/UseField.md` at line 12, The
"Defined in:" source link in the Preact UseField.md is pointing to the React
implementation; update the reference to point to the Preact implementation by
replacing the target URL `packages/react-form/src/useField.tsx` with
`packages/preact-form/src/useField.tsx` in the UseField.md file so the "Defined
in:" link correctly references the Preact `useField.tsx` source.

6-6: ⚠️ Potential issue | 🟡 Minor

Verify typo in type parameter name: "TPatentSubmitMeta".

The type parameter is spelled "TPatentSubmitMeta" which appears to be a typo for "TParentSubmitMeta". This appears consistently throughout the documentation.

Also applies to: 64-64

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

In `@docs/framework/preact/reference/type-aliases/UseField.md` at line 6, The type
parameter name "TPatentSubmitMeta" in the UseField type alias is a typo; update
the type parameter declaration and every occurrence of "TPatentSubmitMeta" to
"TParentSubmitMeta" (e.g., in the UseField() generic parameter list and all
references within this doc entry) so the name consistently reads
TParentSubmitMeta across the documentation.
docs/framework/preact/reference/interfaces/WithFormProps.md (1)

8-8: ⚠️ Potential issue | 🔴 Critical

Incorrect source file references for Preact documentation.

The "Defined in:" links reference packages/react-form/src/createFormHook.tsx but this is Preact framework documentation. These should point to packages/preact-form/src/createFormHook.tsx instead.

Also applies to: 84-84, 94-94

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

In `@docs/framework/preact/reference/interfaces/WithFormProps.md` at line 8,
Update the incorrect "Defined in:" repository links in the WithFormProps.md
Preact doc: replace any references that point to
packages/react-form/src/createFormHook.tsx with the corresponding
packages/preact-form/src/createFormHook.tsx path so the Preact docs link to the
Preact source; search the same WithFormProps.md for other "Defined in:"
occurrences (including the other instances reported) and update them the same
way to ensure all source links reference the preact-form implementation.
🟡 Minor comments (35)
packages/preact-form/README.md-21-21 (1)

21-21: ⚠️ Potential issue | 🟡 Minor

Malformed URL in Best of JS badge.

The URL contains TanStack%form which appears to be a typo. It should likely be TanStack%2Fform (URL-encoded slash) to correctly reference TanStack/form.

Proposed fix
-</a><a href="https://bestofjs.org/projects/tanstack-form"><img alt="Best of JS" src="https://img.shields.io/endpoint?url=https://bestofjs-serverless.now.sh/api/project-badge?fullName=TanStack%form%26since=daily" /></a><a href="https://github.com/TanStack/form/" target="\_parent">
+</a><a href="https://bestofjs.org/projects/tanstack-form"><img alt="Best of JS" src="https://img.shields.io/endpoint?url=https://bestofjs-serverless.now.sh/api/project-badge?fullName=TanStack%2Fform%26since=daily" /></a><a href="https://github.com/TanStack/form/" target="\_parent">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/README.md` at line 21, The Best of JS badge URL contains
a malformed encoded segment "TanStack%form" in the href; locate the badge
anchor/URL (the string containing "TanStack%form" in the README) and replace
that segment with the properly URL-encoded slash "TanStack%2Fform" so the badge
points to "TanStack/form" (ensure the full href uses "TanStack%2Fform" rather
than "TanStack%form").
docs/framework/preact/reference/interfaces/UseFieldOptions.md-8-8 (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Source file links incorrectly point to react-form instead of preact-form package.

All preact documentation files reference packages/react-form/src/ but should reference packages/preact-form/src/ instead. The preact-form package has its own source files, and the documentation links should point there.

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

In `@docs/framework/preact/reference/interfaces/UseFieldOptions.md` at line 8, The
documentation links in the Preact reference (e.g., UseFieldOptions.md)
incorrectly point to "packages/react-form/src/" instead of the Preact package;
update any occurrences of the string "packages/react-form/src/" in the Preact
docs to "packages/preact-form/src/" so the "Defined in:" source file links
resolve to the correct package (check files like UseFieldOptions.md and other
docs under docs/framework/preact/reference for similar links and replace them).
docs/framework/preact/reference/type-aliases/ServerFormState.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Update the source file link to reference preact-form instead of react-form.

The ServerFormState type is defined in packages/preact-form/src/types.ts. The documentation link should point to the preact-form package source for consistency with the Preact framework documentation.

Change the "Defined in:" link from packages/react-form/src/types.ts:120 to packages/preact-form/src/types.ts (verify the correct line number in preact-form).

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

In `@docs/framework/preact/reference/type-aliases/ServerFormState.md` at line 12,
Update the "Defined in:" source link for the ServerFormState doc entry to point
to the Preact package source instead of React: locate the ServerFormState
reference in docs/framework/preact/reference/type-aliases/ServerFormState.md and
replace the existing link to packages/react-form/src/types.ts:120 with the
corresponding packages/preact-form/src/types.ts (adjusting the line number to
the correct line where ServerFormState is defined in preact-form's types.ts) so
the documentation correctly references the preact-form source.
docs/framework/preact/guides/submission-handling.md-67-76 (1)

67-76: ⚠️ Potential issue | 🟡 Minor

Normalize product branding to TanStack.

Use TanStack Form consistently (Lines 67 and 76 currently use Tanstack).

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

In `@docs/framework/preact/guides/submission-handling.md` around lines 67 - 76,
Replace inconsistent product branding "Tanstack Form" with the correct "TanStack
Form" in the documentation text where it appears (the sentences explaining
Standard Schema support and the note about input type). Update the two
occurrences of the phrase "Tanstack Form" so both read "TanStack Form" to ensure
consistent branding across the guide (look for the phrases around the Standard
Schema/validation paragraph and the comment line about input type).
docs/framework/preact/reference/functions/useStore.md-47-47 (1)

47-47: ⚠️ Potential issue | 🟡 Minor

Avoid duplicate heading text for overload sections.

Line 47 repeats ## Call Signature, which triggers MD024. Rename overload sections (e.g., ## Call Signature (Store) / ## Call Signature (Derived)).

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

In `@docs/framework/preact/reference/functions/useStore.md` at line 47, The
duplicate "## Call Signature" heading in the useStore documentation causes
MD024; update the overload section headings to unique names (for example "##
Call Signature (Store)" and "## Call Signature (Derived)") so each overload
under useStore has a distinct heading; locate the overload sections in
docs/framework/preact/reference/functions/useStore.md and rename the second and
any subsequent "## Call Signature" headings accordingly to avoid the lint error.
docs/framework/preact/reference/variables/Field.md-14-16 (1)

14-16: ⚠️ Potential issue | 🟡 Minor

Use Preact terminology on this Preact API page.

Line 14 says “React component”, which is inconsistent for the Preact reference section. Please update wording to “Preact component” (or framework-neutral “component”).

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

In `@docs/framework/preact/reference/variables/Field.md` around lines 14 - 16, The
documentation text for the Field component incorrectly uses "React component";
update the wording in the Field.md description (the sentence describing what
Field returns) to use Preact terminology — e.g., change "React component" to
"Preact component" (or use the framework-neutral term "component") so the
description for Field and the mention of useField remains consistent with the
Preact reference.
docs/framework/preact/reference/variables/Field.md-108-116 (1)

108-116: ⚠️ Potential issue | 🟡 Minor

Fix generic type parameter typo (TPatentSubmitMeta).

TPatentSubmitMeta appears to be a typo and makes the signature harder to trust/read. Please rename consistently (likely TParentSubmitMeta or TSubmitMeta based on source type naming).

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

In `@docs/framework/preact/reference/variables/Field.md` around lines 108 - 116,
The docs show a typo in the generic parameter name "TPatentSubmitMeta" used
inside the FieldComponentProps generic list; rename that identifier consistently
to "TParentSubmitMeta" (or "TSubmitMeta" if that matches your source types)
across this documentation entry and any corresponding type references so the
signature reads FieldComponentProps<..., TParentSubmitMeta> and any
cross-references are updated; verify the underlying source/type names (e.g., the
type exported in code) and make the doc generic name match that exact exported
type name.
docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md-8-8 (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Correct the “Defined in” path for Preact docs

Line 8 references packages/react-form/src/types.ts, which is inconsistent for this Preact reference page.

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

In `@docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md` at line
8, The "Defined in" link in the Preact doc UseFieldOptionsBound references the
React package path; update that reference to point to the Preact source file
instead (replace packages/react-form/src/types.ts:81 with the correct Preact
source path, e.g., packages/preact-form/src/types.ts:81) in the
UseFieldOptionsBound doc so the "Defined in" link resolves to the Preact
implementation.
docs/framework/preact/reference/interfaces/ReactFormApi.md-8-8 (1)

8-8: ⚠️ Potential issue | 🟡 Minor

Use a Preact-relevant source link in this page

Line 8 currently points to packages/react-form/...; this is likely the wrong source attribution for a Preact reference page.

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

In `@docs/framework/preact/reference/interfaces/ReactFormApi.md` at line 8, The
source link in the Preact reference page ReactFormApi.md points to the React
implementation (packages/react-form/src/useForm.tsx); update that link to the
Preact-specific source file for the same symbol (replace the React package path
with the Preact package counterpart, e.g., change
packages/react-form/src/useForm.tsx to the corresponding
packages/preact-form/src/useForm.tsx or the actual Preact file that defines
useForm) so the "Defined in:" link references the Preact implementation of
useForm.
docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md-37-39 (1)

37-39: ⚠️ Potential issue | 🟡 Minor

Replace React-version-specific metadata on a Preact page

Line 39 shows 16.8.0, which reads like React versioning and can mislead in this framework section. Prefer package-version context or remove this section.

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

In `@docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md`
around lines 37 - 39, The "## Version" metadata block currently lists "16.8.0"
(a React-style version) which is misleading in this Preact doc; either remove
the "## Version" section entirely or replace "16.8.0" with the appropriate
Preact/package version string or a generic package-version label. Locate the "##
Version" header and the literal "16.8.0" in useIsomorphicLayoutEffect.md and
update the text to reflect package-version context (e.g., "Package version:
x.y.z" or the correct Preact release) or delete the header and value if
versioning isn't applicable.
docs/framework/preact/reference/interfaces/ReactFormApi.md-72-72 (1)

72-72: ⚠️ Potential issue | 🟡 Minor

Align framework wording in the field description

Line 72 says “A React component…”. In this section it should be phrased as a Preact component (or framework-neutral wording).

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

In `@docs/framework/preact/reference/interfaces/ReactFormApi.md` at line 72, The
wording in the field description for ReactFormApi incorrectly says "A React
component…"; update the description in the ReactFormApi documentation to use
framework-neutral wording or explicitly say "A Preact component" (e.g., change
"A React component to render form fields." to "A Preact component to render form
fields." or "A component to render form fields.") so the description matches the
framework; edit the ReactFormApi interface doc entry (the paragraph under the
ReactFormApi header) to implement this wording change.
docs/framework/preact/reference/functions/createFormHookContexts.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Update source attribution to match Preact package docs

Line 12 currently links to packages/react-form/...; this should be aligned with the Preact package/source context.

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

In `@docs/framework/preact/reference/functions/createFormHookContexts.md` at line
12, The documentation source attribution currently points to the React package;
update the link in createFormHookContexts.md (the "Defined in" reference) to the
corresponding Preact source (e.g., change
packages/react-form/src/createFormHook.tsx:95 to
packages/preact-form/src/createFormHook.tsx:95) so the "Defined in" attribution
correctly references the Preact implementation of createFormHook
(createFormHook.tsx).
docs/framework/preact/reference/functions/useForm.md-12-15 (1)

12-15: ⚠️ Potential issue | 🟡 Minor

Make this reference consistently Preact-oriented

Line 12 points to packages/react-form/... and Line 14 says “React Hook”. In the Preact section, both should be Preact-specific (or explicitly framework-neutral).

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

In `@docs/framework/preact/reference/functions/useForm.md` around lines 12 - 15,
The docs reference for useForm is React-specific; update the reference to be
Preact-oriented by changing the source link from packages/react-form/... to the
Preact implementation (e.g., packages/preact-form/src/useForm.tsx) and update
the description text from “A custom React Hook” to either “A custom Preact Hook”
or a framework-neutral phrase like “A custom Hook that returns an extended
instance of the FormApi class”; ensure the symbol name useForm and FormApi
remain unchanged in the text.
docs/framework/preact/guides/debugging.md-39-39 (1)

39-39: ⚠️ Potential issue | 🟡 Minor

Minor grammar fix in TypeScript explanation

Line 39: “TypeScript struggled” should be present tense (“struggles”) in this guidance context.

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

In `@docs/framework/preact/guides/debugging.md` at line 39, Replace the past-tense
phrase "TypeScript struggled" with present tense "TypeScript struggles" in the
sentence that currently reads "There are some edge cases where TypeScript
struggled with the complexity of our types." to keep the guidance in present
tense; locate the sentence by searching for the exact phrase "TypeScript
struggled" in the docs/framework/preact/guides/debugging.md content and update
it to "TypeScript struggles".
docs/config.json-505-533 (1)

505-533: ⚠️ Potential issue | 🟡 Minor

Preact API nav is missing links to newly added reference pages

This block only exposes a subset of the new Preact reference docs. Pages added in this PR (e.g., createFormHookContexts, ReactFormApi, UseFieldOptionsBound, useIsomorphicLayoutEffect) should also be included to avoid orphaned docs.

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

In `@docs/config.json` around lines 505 - 533, The Preact nav block currently only
includes a subset of reference pages; add entries for the newly added reference
pages so they aren't orphaned — specifically add child items with labels and
"to" targets for createFormHookContexts (e.g.,
"framework/preact/reference/functions/createFormHookContexts" or appropriate
path), ReactFormApi (e.g., "framework/preact/reference/interfaces/ReactFormApi"
or appropriate path), UseFieldOptionsBound (e.g.,
"framework/preact/reference/type-aliases/UseFieldOptionsBound"), and
useIsomorphicLayoutEffect (e.g.,
"framework/preact/reference/functions/useIsomorphicLayoutEffect") alongside the
existing items under the "preact" -> "children" array in the same nav block
(matching naming convention used for other entries).
docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Fix framework source attribution in this Preact reference

Line 12 links to packages/react-form/..., which is confusing in a Preact API page. Prefer the packages/preact-form/... source (or a framework-neutral source note).

Suggested docs fix
-Defined in: [packages/react-form/src/useIsomorphicLayoutEffect.ts:3](https://github.com/TanStack/form/blob/main/packages/react-form/src/useIsomorphicLayoutEffect.ts#L3)
+Defined in: [packages/preact-form/src/useIsomorphicLayoutEffect.ts:3](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useIsomorphicLayoutEffect.ts#L3)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md` at
line 12, The reference currently points to the React package source
(packages/react-form/src/useIsomorphicLayoutEffect.ts) which is misleading on
the Preact API page; update the "Defined in" link in
docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md to point
to the Preact implementation
(packages/preact-form/src/useIsomorphicLayoutEffect.ts) or replace the link with
a framework-neutral note that cites the shared implementation location, ensuring
the displayed file path and URL reflect the preact-form package or neutral
wording so readers aren’t directed to the react-form package.
docs/framework/preact/guides/listeners.md-71-71 (1)

71-71: ⚠️ Potential issue | 🟡 Minor

Fix heading level for "Built-in Debouncing" section.

The "Built-in Debouncing" section uses ### (h3) but should use ## (h2) since it's a top-level section, not a subsection of the preceding example. As per static analysis, heading levels should only increment by one level at a time.

📝 Proposed fix
-### Built-in Debouncing
+## Built-in Debouncing
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/listeners.md` at line 71, Change the heading
level for the "Built-in Debouncing" section from an h3 to an h2 so heading
levels only increment by one; locate the heading text "Built-in Debouncing" in
docs and replace the leading "###" with "##" to make it a top-level section
rather than a subsection.
docs/framework/preact/reference/type-aliases/FieldComponent.md-6-6 (1)

6-6: ⚠️ Potential issue | 🟡 Minor

Fix typo in type parameter name: "TPatentSubmitMeta" → "TParentSubmitMeta"

The type parameter is misspelled as "TPatentSubmitMeta" and should be "TParentSubmitMeta" to match the correct spelling used throughout the codebase (e.g., in packages/form-core/src/FieldApi.ts). This typo appears at line 6 (in the title) and line 65 (in the type parameters section).

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

In `@docs/framework/preact/reference/type-aliases/FieldComponent.md` at line 6,
The type parameter name is misspelled in the FieldComponent declaration and its
type-parameters list: replace the incorrect "TPatentSubmitMeta" with the correct
"TParentSubmitMeta" wherever it appears in the FieldComponent definition and
related type-parameter section so it matches the spelling used in FieldApi and
the rest of the codebase; update both the title and the detailed type parameters
block for the FieldComponent type alias to use TParentSubmitMeta.
docs/framework/preact/guides/focus-management.md-133-133 (1)

133-133: ⚠️ Potential issue | 🟡 Minor

Type mismatch: value prop expects string but field.state.value is a number.

The TextInput component expects a string for value, but defaultValues.age is 0 (number). This should be converted to a string.

Proposed fix
-              value={field.state.value}
+              value={String(field.state.value)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/focus-management.md` at line 133, The
TextInput's value prop is receiving a number (field.state.value /
defaultValues.age) but expects a string; update where TextInput is rendered
(reference TextInput and field.state.value/defaultValues.age) to coerce the
numeric value to a string (e.g., use String(field.state.value) or
field.state.value?.toString() or a fallback like '' for null/undefined) so the
prop type matches and the input remains controlled.
docs/framework/preact/reference/functions/useField.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Incorrect source link points to React package instead of Preact.

The "Defined in" link references packages/react-form/src/useField.tsx but this documentation is for the Preact integration. It should point to the Preact package source file.

Proposed fix
-Defined in: [packages/react-form/src/useField.tsx:139](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L139)
+Defined in: [packages/preact-form/src/useField.tsx:139](https://github.com/TanStack/form/blob/main/packages/preact-form/src/useField.tsx#L139)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/reference/functions/useField.md` at line 12, Update the
"Defined in" source link in
docs/framework/preact/reference/functions/useField.md so it points to the Preact
package source instead of the React one: replace the reference to
packages/react-form/src/useField.tsx with the Preact file path
(packages/preact-form/src/useField.tsx) so the "Defined in" link correctly
targets the Preact implementation of useField.
docs/framework/preact/quick-start.md-109-110 (1)

109-110: ⚠️ Potential issue | 🟡 Minor

Validation logic inconsistent with error message.

The validator returns an error when value is not greater than 13, but the error message says "Must be 13 or older". This means a 13-year-old would incorrectly receive an error. The condition should use >= to match the message.

Proposed fix
         onChange: ({ value }) =>
-          value > 13 ? undefined : 'Must be 13 or older',
+          value >= 13 ? undefined : 'Must be 13 or older',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/quick-start.md` around lines 109 - 110, The validation
logic in the onChange validator currently uses value > 13 but the message says
"Must be 13 or older", so update the validator used in the onChange handler to
use value >= 13 (so 13 is accepted) and keep the error message 'Must be 13 or
older' unchanged; locate the onChange function in the Quick Start Preact example
and replace the greater-than check with a greater-than-or-equal check.
docs/framework/preact/guides/reactivity.md-34-47 (1)

34-47: ⚠️ Potential issue | 🟡 Minor

Code example has multiple issues that would prevent it from working.

  1. form.Field is missing the required name prop
  2. field.state.lastName should be field.state.value - the field's value is accessed via state.value, not by the field name
  3. onInput={field.handleChange} won't work - handleChange expects the new value directly, not an event object
Proposed fix
 <form.Subscribe
   selector={(state) => state.values.firstName}
   children={(firstName) => (
-    <form.Field>
+    <form.Field name="lastName">
       {(field) => (
         <input
           name="lastName"
-          value={field.state.lastName}
-          onInput={field.handleChange}
+          value={field.state.value}
+          onInput={(e) => field.handleChange(e.target.value)}
         />
       )}
     </form.Field>
   )}
 />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/reactivity.md` around lines 34 - 47, The example
has three bugs: update the form.Field invocation to include the required name
prop (e.g., name="lastName"); read the field value from field.state.value
instead of field.state.lastName; and change the input handler so it passes the
new value to field.handleChange (replace passing the event with calling
handleChange with the input's current value, e.g., extract
event.currentTarget.value and pass that to field.handleChange). These changes
touch form.Subscribe, its selector, the form.Field component, the use of
field.state, and the onInput handler for the input element.
docs/framework/preact/reference/functions/useField.md-106-108 (1)

106-108: ⚠️ Potential issue | 🟡 Minor

Fix type parameter name: TPatentSubmitMeta should be TParentSubmitMeta.

This typo appears in the source code (packages/preact-form/src/useField.tsx and packages/react-form/src/useField.tsx) and is propagated to the documentation. The correct naming TParentSubmitMeta is consistently used across vue, svelte, and core form implementations.

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

In `@docs/framework/preact/reference/functions/useField.md` around lines 106 -
108, The type parameter name is misspelled as TPatentSubmitMeta (should be
TParentSubmitMeta) in the useField implementations and the docs; update every
occurrence of the generic/type parameter from TPatentSubmitMeta to
TParentSubmitMeta in the useField function/type declarations and usages (e.g.,
the useField generic signature and any references within packages/preact-form
and packages/react-form) and correct the documentation entry (useField.md) to
match the canonical TParentSubmitMeta name so all implementations are
consistent.
docs/framework/preact/reference/type-aliases/LensFieldComponent.md-15-15 (1)

15-15: ⚠️ Potential issue | 🟡 Minor

Source path incorrectly references react-form instead of preact-form.

The source definition points to packages/react-form/src/useField.tsx but this is Preact documentation. Should reference packages/preact-form/src/useField.tsx.

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

In `@docs/framework/preact/reference/type-aliases/LensFieldComponent.md` at line
15, The documentation entry in LensFieldComponent.md incorrectly links the
source to packages/react-form/src/useField.tsx:598; update the source reference
to packages/preact-form/src/useField.tsx:598 inside
docs/framework/preact/reference/type-aliases/LensFieldComponent.md so the Preact
docs point to the correct source file (replace the react-form path with
preact-form in the Defined in link).
docs/framework/preact/reference/type-aliases/LensFieldComponent.md-19-34 (1)

19-34: ⚠️ Potential issue | 🟡 Minor

Duplicate "## Type Parameters" heading.

There are two ## Type Parameters headings (lines 19 and 34), which creates confusing document structure. The first section (lines 19-32) documents TLensData, TParentSubmitMeta, and ExtendedApi, while the second (line 34+) documents TName, TData, and validator generics. Consider renaming the second heading to distinguish it, e.g., "## Call Signature Type Parameters".

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

In `@docs/framework/preact/reference/type-aliases/LensFieldComponent.md` around
lines 19 - 34, The document contains two identical "## Type Parameters"
headings; rename the second heading (the one documenting TName, TData and
validator generics) to a distinct title such as "## Call Signature Type
Parameters" (or another descriptive phrase) to avoid duplication and clarify
structure; update the heading that surrounds the TName, TData and validator
generic entries and ensure any cross-references point to the new heading while
leaving TLensData, TParentSubmitMeta and ExtendedApi unchanged.
packages/preact-form/tests/useForm.test.tsx-918-919 (1)

918-919: ⚠️ Potential issue | 🟡 Minor

ESLint rule @eslint-react/no-array-index-key is not defined.

The disable comment references a rule that isn't configured in the project's ESLint setup. Either add the @eslint-react plugin to the ESLint configuration, or if this was copied from the React tests, update to use the correct rule name for this project's setup (possibly react/no-array-index-key or remove the comment if no such rule exists).

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

In `@packages/preact-form/tests/useForm.test.tsx` around lines 918 - 919, The
ESLint disable comment referencing `@eslint-react/no-array-index-key` is invalid;
update the disable or remove it: either change the comment to the correct rule
name used in this project (e.g., react/no-array-index-key) or simply delete the
disable line above the JSX element <form.Field key={i} name={`foo[${i}].name`}>;
ensure the fix targets the test file's JSX usage of key={i} on form.Field so the
linter no longer references the non-existent `@eslint-react` plugin.
docs/framework/preact/guides/basic-concepts.md-86-95 (1)

86-95: ⚠️ Potential issue | 🟡 Minor

Invalid ESLint rule configuration syntax.

The ESLint rule example uses true as the severity, which is not a valid ESLint severity level. ESLint expects "error", "warn", "off", or numeric values 2, 1, 0.

📝 Proposed fix
 ```json
   "rules": {
     "react/no-children-prop": [
-      true,
+      "error",
       {
         "allowFunctions": true
       }
     ],
   }
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/framework/preact/guides/basic-concepts.md around lines 86 - 95, The
ESLint rule example uses an invalid severity value; update the
"react/no-children-prop" rule configuration in the shown JSON to use a valid
severity ("error", "warn", "off" or numeric 2/1/0) instead of true so ESLint
accepts the config; locate the rule entry for "react/no-children-prop" and
replace the first array element (currently true) with a valid severity like
"error" while keeping the options object (allowFunctions) unchanged.


</details>

</blockquote></details>
<details>
<summary>packages/preact-form/src/useFieldGroup.tsx-76-79 (1)</summary><blockquote>

`76-79`: _⚠️ Potential issue_ | _🟡 Minor_

**JSDoc comment incorrectly references "React" instead of "Preact".**

The comment says "A React component" but this is the Preact integration package.

<details>
<summary>📝 Proposed fix</summary>

```diff
     /**
-     * A React component to render form fields. With this, you can render and manage individual form fields.
+     * A Preact component to render form fields. With this, you can render and manage individual form fields.
      */
     Field: LensFieldComponent<TFieldGroupData, TSubmitMeta>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/src/useFieldGroup.tsx` around lines 76 - 79, The JSDoc
for the Field export incorrectly says "A React component"; update the comment to
reference Preact instead—e.g., change "A React component to render form fields"
to "A Preact component to render form fields" (or "A Preact-compatible
component") to accurately describe Field: LensFieldComponent<TFieldGroupData,
TSubmitMeta> in useFieldGroup.tsx.
docs/framework/preact/guides/form-composition.md-466-469 (1)

466-469: ⚠️ Potential issue | 🟡 Minor

The prop name here should be fields.

Line 469 tells readers to change the field property, but the API and the examples below use fields. As written, this points people at a non-existent prop.

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

In `@docs/framework/preact/guides/form-composition.md` around lines 466 - 469, The
documentation incorrectly refers to a non-existent prop named "field"; update
the wording so it instructs readers to change the "fields" property instead
(update the sentence in the "Mapping field group values to a different field"
section and any nearby example code or prose that mentions `field` to use
`fields`), ensuring consistency with the API and the examples that follow.
docs/framework/preact/reference/functions/createFormHook.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Point the "Defined in" link at the Preact source.

Line 12 still links to packages/react-form/src/createFormHook.tsx, so this Preact reference page sends readers to the wrong package. If this page is generated, please fix the source mapping/template rather than patching the markdown by hand.

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

In `@docs/framework/preact/reference/functions/createFormHook.md` at line 12, The
"Defined in" link on the Preact page points to the React package; update the
docs generator/template that produces createFormHook.md so it resolves the
source file for the Preact variant instead of hardcoding the React path. Locate
the template or mapping code that emits the "Defined in" link (the logic that
builds the repository path for createFormHook) and change it to use the Preact
package source (e.g., packages/preact-form/src/createFormHook.tsx) when
rendering the Preact reference page (createFormHook.md) rather than
packages/react-form/src/createFormHook.tsx; ensure the generator uses the
package type or component namespace to pick the correct package path.
docs/framework/preact/guides/form-composition.md-258-263 (1)

258-263: ⚠️ Potential issue | 🟡 Minor

These snippets are spreading the formOptions factory, not the options object.

Lines 260, 290, and 300 use ...formOptions, but formOptions is the helper function. These examples need the object returned by it (formOpts or similar), otherwise they fail as soon as someone copies them.

Also applies to: 285-300

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

In `@docs/framework/preact/guides/form-composition.md` around lines 258 - 263, The
examples are spreading the helper function formOptions instead of the returned
options object; update the snippets (e.g., in RouteComponent where useAppForm is
called) to call the factory and spread its result (assign const formOpts =
formOptions(...) or call formOptions() and spread formOpts) so useAppForm
receives the actual options object rather than the function itself; apply the
same change to the other affected examples around the 285–300 range.
docs/framework/preact/guides/form-composition.md-573-577 (1)

573-577: ⚠️ Potential issue | 🟡 Minor

Make the lazy import match the file name used above.

The previous snippet defines src/components/text-field.tsx, but Line 577 imports ../components/text-fields.tsx. One of those names needs to change or this example won't resolve.

Suggested fix
-const TextField = lazy(() => import('../components/text-fields.tsx'))
+const TextField = lazy(() => import('../components/text-field.tsx'))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/form-composition.md` around lines 573 - 577, The
lazy import path for TextField is inconsistent with the component name used
earlier: change the import in the createFormHook file so the lazy call matches
the actual file name (e.g., import '../components/text-field.tsx' to align with
src/components/text-field.tsx) by updating the lazy(() =>
import('../components/text-fields.tsx')) line to the correct filename that
matches the component (ensuring the TextField constant continues to reference
the lazy import).
packages/preact-form/tests/createFormHook.test-d.tsx-435-439 (1)

435-439: ⚠️ Potential issue | 🟡 Minor

This @ts-expect-error is failing for the wrong reason.

Line 438 passes name="" instead of fields="person", so this stays green because of an unknown/missing prop rather than because incompatibleAppForm violates the subset type you're trying to cover.

Suggested fix
-        name=""
+        fields="person"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/tests/createFormHook.test-d.tsx` around lines 435 - 439,
The `@ts-expect-error` on the FormGroup test is masking the wrong problem because
the component is given name="" instead of the intended fields prop; update the
test to pass fields="person" (or the correct fields value used elsewhere) to the
FormGroup invocation so the type-checker fails due to incompatibleAppForm not
matching the expected subset type (keep form={incompatibleAppForm} and
prop1="test" as-is), ensuring the error is caused by the form type mismatch
rather than a missing/unknown prop.
docs/framework/preact/guides/form-composition.md-154-157 (1)

154-157: ⚠️ Potential issue | 🟡 Minor

Use a JSX comment inside <form.AppForm>.

The // ... lines here are parsed as JSX children, so this snippet won't compile as copied.

Suggested fix
     <form.AppForm>
-      // Notice the `AppForm` component wrapper; `AppForm` provides the required
-      context
+      {/* Notice the `AppForm` component wrapper; `AppForm` provides the required context */}
       <form.SubscribeButton label="Submit" />
     </form.AppForm>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/form-composition.md` around lines 154 - 157, The
JSX snippet uses JavaScript line comments inside a JSX element which become
children and break compilation; update the <form.AppForm> example so the
explanatory note is a proper JSX comment (e.g., replace the "// Notice..." line
with a {/* ... */} comment) or remove the inline comment entirely, keeping the
component wrapper and <form.SubscribeButton label="Submit" /> intact (look for
AppForm, form.AppForm, and SubscribeButton to locate the snippet).
packages/preact-form/src/useField.tsx-222-231 (1)

222-231: ⚠️ Potential issue | 🟡 Minor

Array-mode selector can miss sparse-array length semantics.

Using Object.keys(value).length can diverge from actual array length for sparse arrays. This can skip expected reactivity updates for array fields that contain holes.

💡 Suggested fix
-  const reactiveStateValue = useStore(
-    fieldApi.store,
-    (opts.mode === 'array'
-      ? (state) => Object.keys((state.value as unknown) ?? []).length
-      : (state) => state.value) as (
-      state: typeof fieldApi.state,
-    ) => TData | number,
-  )
+  const reactiveStateValue = useStore(
+    fieldApi.store,
+    (opts.mode === 'array'
+      ? (state) =>
+          Array.isArray(state.value) ? state.value.length : 0
+      : (state) => state.value) as (
+      state: typeof fieldApi.state,
+    ) => TData | number,
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/src/useField.tsx` around lines 222 - 231, The selector
used for array mode in useStore (reactiveStateValue) uses
Object.keys((state.value) ?? []).length which misrepresents sparse arrays;
update the selector so when opts.mode === 'array' it checks if state.value is an
actual array and returns (state.value as any).length (with safe null/undefined
handling), falling back to Object.keys(...) length only for non-array
values—i.e., change the array-mode branch in the useStore selector to prefer
Array.isArray(state.value) ? state.value.length : Object.keys((state.value ??
[])).length to preserve sparse-array length semantics for fieldApi.store
reactivity.
🧹 Nitpick comments (6)
packages/preact-form/eslint.config.js (1)

12-16: Rule override lacks files scope and may apply globally.

The rule to disable @eslint-react/no-use-context is in a separate config object without a files pattern. While this likely works since the rule only applies to files the React plugin processes, it would be cleaner to merge it into the same config block or add matching files for consistency.

Suggested consolidation
 export default [
   ...rootConfig,
   {
     files: ['**/*.{ts,tsx}'],
     ...pluginReact.configs.recommended,
+    rules: {
+      ...pluginReact.configs.recommended.rules,
+      '@eslint-react/no-use-context': 'off',
+    },
   },
-  {
-    rules: {
-      '@eslint-react/no-use-context': 'off',
-    },
-  },
 ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/eslint.config.js` around lines 12 - 16, The ESLint rule
override for '@eslint-react/no-use-context' is declared in a separate config
object without a files scope, which can make it apply more broadly and is
inconsistent; merge this rule into the primary rules block (the existing rules
object in eslint.config.js) or add a matching files array for the separate
config so the override is scoped; update the rules entry for
'@eslint-react/no-use-context' within the main rules object (or add files: [...]
alongside the rule) to ensure consistent, scoped configuration.
docs/framework/preact/guides/debugging.md (1)

13-13: Use a current/framework-appropriate docs link in the warning text

Line 13 embeds a legacy reactjs.org URL. Consider updating to a current link (or a framework-neutral explanation) for better guidance quality.

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

In `@docs/framework/preact/guides/debugging.md` at line 13, The embedded warning
string "Warning: A component is changing an uncontrolled input to be controlled.
... More info: https://reactjs.org/link/controlled-components" should be updated
to use a current, framework-appropriate link or a neutral explanation; locate
that exact warning text in docs/framework/preact/guides/debugging.md and replace
the reactjs.org URL with either the official Preact guidance URL (or a stable
framework-neutral docs page) and/or append a brief in-place explanation about
controlled vs uncontrolled inputs so readers aren’t directed to a legacy
React-specific link.
docs/framework/preact/guides/ui-libraries.md (1)

54-60: Using defaultValue creates an uncontrolled component.

Using defaultValue instead of value makes the TextInput uncontrolled, meaning the component won't update when form state changes programmatically (e.g., via form.reset() or field.setValue()). For fully controlled behavior, use value instead.

Proposed fix
             <TextInput
-              defaultValue={state.value}
+              value={state.value}
               onInput={(e) => handleChange(e.target.value)}
               onBlur={handleBlur}
               placeholder="Enter your name"
             />

The same applies to the Material UI example at Lines 102-103.

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

In `@docs/framework/preact/guides/ui-libraries.md` around lines 54 - 60, The
examples use defaultValue which makes the inputs uncontrolled; change the
TextInput props to use value={state.value} (instead of defaultValue) so the
component is fully controlled and will reflect programmatic updates, keep
onInput={(e) => handleChange(e.target.value)} and onBlur={handleBlur} as-is to
drive state updates via handleChange/handleBlur; apply the same change to the
Material UI example (replace defaultValue with value tied to the same form
state/field.setValue source) so both inputs remain controlled by the form state.
packages/preact-form/tests/useForm.test-d.tsx (1)

4-4: Rename ReactFormExtendedApi to FormExtendedApi or PreactFormExtendedApi.

The Preact package defines its own ReactFormExtendedApi type independently from the React package. The "React" prefix in the Preact package is misleading and reduces clarity. Consider using a more generic or Preact-specific name.

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

In `@packages/preact-form/tests/useForm.test-d.tsx` at line 4, The type name
ReactFormExtendedApi in the Preact package is misleading; rename the type to
either FormExtendedApi or PreactFormExtendedApi and update all usages and
exports accordingly. Locate the type declaration named ReactFormExtendedApi in
src/useForm and rename it, update the import in tests (useForm.test-d.tsx) to
the new name, and update any re-exports (e.g., package index or barrel files)
and references in functions like useForm to use the new identifier so the public
API remains consistent.
docs/framework/preact/guides/validation.md (1)

34-35: Consider using e.currentTarget for consistency with Preact best practices.

The documentation uses e.target.valueAsNumber and e.target.value in examples. While this works, e.currentTarget provides better TypeScript type inference in Preact/React event handlers since it's guaranteed to be the element the handler is attached to. Consider updating for consistency with the example in examples/preact/simple/src/index.tsx which uses e.currentTarget.value.

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

In `@docs/framework/preact/guides/validation.md` around lines 34 - 35, Update the
event handler to use e.currentTarget for better TypeScript inference: replace
uses of e.target.valueAsNumber with e.currentTarget.valueAsNumber in the onInput
handler that calls field.handleChange; ensure other examples (where
e.target.value is used) are similarly updated to e.currentTarget.value to match
the pattern used in examples/preact/simple/src/index.tsx.
packages/preact-form/src/useField.tsx (1)

351-352: Docs still reference React in the Preact adapter.

These comments mention “React element/component” in a Preact package. Consider renaming to framework-neutral or Preact wording for consistency.

Also applies to: 682-683

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

In `@packages/preact-form/src/useField.tsx` around lines 351 - 352, The JSDoc for
the children param in useField.tsx and the similar comment around the other
occurrence still mention “React element/component”; update those comments to be
framework-neutral or Preact-specific (e.g., “Preact element/component” or “JSX
element/component”) so the Preact adapter docs are consistent—search for the
JSDoc on the children parameter (and the other comment referenced) in
useField.tsx and replace “React” wording accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 747bd639-a127-45a5-8cf4-1e11b0083504

📥 Commits

Reviewing files that changed from the base of the PR and between 4e7c8a6 and b8189a9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (65)
  • docs/config.json
  • docs/framework/preact/guides/arrays.md
  • docs/framework/preact/guides/async-initial-values.md
  • docs/framework/preact/guides/basic-concepts.md
  • docs/framework/preact/guides/custom-errors.md
  • docs/framework/preact/guides/debugging.md
  • docs/framework/preact/guides/dynamic-validation.md
  • docs/framework/preact/guides/focus-management.md
  • docs/framework/preact/guides/form-composition.md
  • docs/framework/preact/guides/linked-fields.md
  • docs/framework/preact/guides/listeners.md
  • docs/framework/preact/guides/reactivity.md
  • docs/framework/preact/guides/submission-handling.md
  • docs/framework/preact/guides/ui-libraries.md
  • docs/framework/preact/guides/validation.md
  • docs/framework/preact/quick-start.md
  • docs/framework/preact/reference/functions/createFormHook.md
  • docs/framework/preact/reference/functions/createFormHookContexts.md
  • docs/framework/preact/reference/functions/useField.md
  • docs/framework/preact/reference/functions/useFieldGroup.md
  • docs/framework/preact/reference/functions/useForm.md
  • docs/framework/preact/reference/functions/useStore.md
  • docs/framework/preact/reference/index.md
  • docs/framework/preact/reference/interfaces/ReactFormApi.md
  • docs/framework/preact/reference/interfaces/UseFieldOptions.md
  • docs/framework/preact/reference/interfaces/UseFieldOptionsBound.md
  • docs/framework/preact/reference/interfaces/WithFieldGroupProps.md
  • docs/framework/preact/reference/interfaces/WithFormProps.md
  • docs/framework/preact/reference/type-aliases/FieldComponent.md
  • docs/framework/preact/reference/type-aliases/LensFieldComponent.md
  • docs/framework/preact/reference/type-aliases/ReactFormExtendedApi.md
  • docs/framework/preact/reference/type-aliases/ServerFormState.md
  • docs/framework/preact/reference/type-aliases/UseField.md
  • docs/framework/preact/reference/variables/Field.md
  • docs/framework/preact/reference/variables/useIsomorphicLayoutEffect.md
  • examples/preact/simple/README.md
  • examples/preact/simple/index.html
  • examples/preact/simple/package.json
  • examples/preact/simple/src/index.tsx
  • examples/preact/simple/tsconfig.json
  • examples/preact/simple/vite.config.ts
  • packages/preact-form/README.md
  • packages/preact-form/eslint.config.js
  • packages/preact-form/package.json
  • packages/preact-form/src/createFormHook.tsx
  • packages/preact-form/src/index.ts
  • packages/preact-form/src/types.ts
  • packages/preact-form/src/useField.tsx
  • packages/preact-form/src/useFieldGroup.tsx
  • packages/preact-form/src/useForm.tsx
  • packages/preact-form/src/useFormId.ts
  • packages/preact-form/src/useIsomorphicLayoutEffect.ts
  • packages/preact-form/tests/createFormHook.test-d.tsx
  • packages/preact-form/tests/createFormHook.test.tsx
  • packages/preact-form/tests/test-setup.ts
  • packages/preact-form/tests/useField.test-d.tsx
  • packages/preact-form/tests/useField.test.tsx
  • packages/preact-form/tests/useForm.test-d.tsx
  • packages/preact-form/tests/useForm.test.tsx
  • packages/preact-form/tests/utils.ts
  • packages/preact-form/tsconfig.docs.json
  • packages/preact-form/tsconfig.json
  • packages/preact-form/vite.config.ts
  • pnpm-workspace.yaml
  • scripts/generate-docs.ts

Comment on lines +20 to +22
import { useForm } from '@tanstack/preact-form'
import { useQuery } from '@tanstack/react-query'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find framework-mismatched TanStack Query imports under Preact docs
rg -n '@tanstack/react-query|@tanstack/solid-query|@tanstack/vue-query' docs/framework/preact

Repository: TanStack/form

Length of output: 161


🏁 Script executed:

#!/bin/bash
# Check if `@tanstack/preact-query` is referenced elsewhere in Preact guides
rg -n '@tanstack/preact-query' docs/framework/preact --max-count=5

# Also check the full context of the problematic file
echo "--- Full content of async-initial-values.md ---"
cat -n docs/framework/preact/guides/async-initial-values.md | head -30

Repository: TanStack/form

Length of output: 1548


🏁 Script executed:

#!/bin/bash
# Check what the correct import should be by looking at other framework guides
echo "=== React guide imports ==="
rg -n 'import.*useQuery' docs/framework/react/guides/async-initial-values.md 2>/dev/null | head -3

echo "=== Vue guide imports ==="
rg -n 'import.*useQuery' docs/framework/vue/guides/async-initial-values.md 2>/dev/null | head -3

echo "=== Solid guide imports ==="
rg -n 'import.*useQuery' docs/framework/solid/guides/async-initial-values.md 2>/dev/null | head -3

# Check if `@tanstack/preact-query` is mentioned anywhere in the repo
echo "=== References to preact-query in repo ==="
rg '@tanstack/preact-query' --type-list | head -20
rg -l '@tanstack/preact-query' 2>/dev/null | head -10

Repository: TanStack/form

Length of output: 690


🏁 Script executed:

#!/bin/bash
# Check if preact-query package exists by looking at package management files
echo "=== Looking for preact-query references in package.json files ==="
find . -name "package.json" -type f | xargs grep -l "preact-query" 2>/dev/null

echo "=== Check main package.json for Query packages ==="
jq '.dependencies | keys[] | select(contains("query"))' package.json 2>/dev/null || cat package.json | grep -i "query" | head -10

echo "=== Check root package references ==="
rg -i "preact.*query|@tanstack.*query" --glob="package.json" --glob="package-lock.json" | head -15

Repository: TanStack/form

Length of output: 403


🏁 Script executed:

#!/bin/bash
# Search for any Solid guide and check its query usage
echo "=== Solid async-initial-values guide ==="
cat -n docs/framework/solid/guides/async-initial-values.md 2>/dev/null | head -30 || echo "File not found"

# Check if there's documentation about Preact + Query
echo "=== Search for Preact Query documentation in repo ==="
rg -i "preact.*query|preact.*tanstack" docs/ --type md | head -10

# Check package ecosystem - does `@tanstack/preact-query` exist?
echo "=== Check if README or docs mention preact-query ==="
rg "@tanstack/preact-query" . 2>/dev/null | head -5 || echo "No `@tanstack/preact-query` found"

Repository: TanStack/form

Length of output: 2127


🌐 Web query:

@tanstack/preact-query npm package

💡 Result:

@tanstack/preact-query is the Preact adapter for TanStack Query (server-state fetching/caching/synchronization). It provides Preact-friendly exports like QueryClient, QueryClientProvider, and hooks such as useQuery, useMutation, etc. [3][4]

Install

npm i `@tanstack/preact-query`
# or pnpm add / yarn add / bun add

[1]

Basic usage

import { render } from 'preact'
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/preact-query'

const queryClient = new QueryClient()

function App() {
  const q = useQuery({
    queryKey: ['todos'],
    queryFn: () => fetch('/api/todos').then(r => r.json()),
  })
  return <pre>{JSON.stringify(q.data, null, 2)}</pre>
}

render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('app')!,
)

[2][3]

Latest version (as of Mar 31, 2026): 5.95.2 [5]

Docs: TanStack Query → Preact section (installation/quick start/guides). [1][2]

References: [1] (tanstack.com) [2] (tanstack.com) [3] (tanstack.com) [4] (tanstack.com) [5] (newreleases.io)

Citations:


Use @tanstack/preact-query instead of @tanstack/react-query.

Line 21 imports from @tanstack/react-query, which is mismatched for this Preact guide. The correct package is @tanstack/preact-query, consistent with how other frameworks (React, Vue, Solid) each have their own TanStack Query adapter.

Suggested diff
 import { useForm } from '@tanstack/preact-form'
-import { useQuery } from '@tanstack/react-query'
+import { useQuery } from '@tanstack/preact-query'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useForm } from '@tanstack/preact-form'
import { useQuery } from '@tanstack/react-query'
import { useForm } from '@tanstack/preact-form'
import { useQuery } from '@tanstack/preact-query'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/framework/preact/guides/async-initial-values.md` around lines 20 - 22,
The import for useQuery is using the React adapter; change the import statement
that currently reads "import { useQuery } from '@tanstack/react-query'" to use
the Preact adapter by importing from "@tanstack/preact-query" so the guide's
code uses the correct TanStack Query package for Preact (update the import where
useQuery is declared alongside useForm).

Comment on lines +71 to +141
## React Native (via compat)

Because React Native doesn't have access to the DOM's `querySelectorAll` API, we need to manually manage the element list
of the inputs. This allows us to focus the first input with an error:

```tsx
import { useRef } from 'preact/hooks'
import { Text, View, TextInput, Button, Alert } from 'react-native'
import { useForm } from '@tanstack/preact-form'
import { z } from 'zod'

export default function App() {
// This can be extracted to a hook that returns the `fields` ref, a `focusFirstField` function, and a `addField` function
const fields = useRef([] as Array<{ input: TextInput; name: string }>)

const form = useForm({
defaultValues: { age: 0 },
validators: {
onChange: z.object({
age: z.number().min(12),
}),
},
onSubmit() {
Alert.alert('Submitted!')
},
onSubmitInvalid({ formApi }) {
const errorMap = formApi.state.errorMap.onChange
const inputs = fields.current

let firstInput
for (const input of inputs) {
if (!input || !input.input) continue
if (!!errorMap[input.name]) {
firstInput = input.input
break
}
}
firstInput?.focus()
},
})

return (
<View style={{ padding: 16 }}>
<form.Field
name="age"
children={(field) => (
<View style={{ marginVertical: 16 }}>
<Text>Age</Text>
<TextInput
keyboardType="numeric"
ref={(input) => {
// fields.current needs to be manually incremented so that we know what fields are rendered or not and in what order
fields.current[0] = { input, name: field.name }
}}
style={{
borderWidth: 1,
borderColor: '#999999',
borderRadius: 4,
marginTop: 8,
padding: 8,
}}
onChangeText={(val) => field.handleChange(Number(val))}
value={field.state.value}
/>
</View>
)}
/>
<Button title="Submit" onPress={form.handleSubmit} />
</View>
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if React docs have a similar section and how it's framed
fd -t f "focus-management.md" --exec cat {}

Repository: TanStack/form

Length of output: 7571


🌐 Web query:

preact/hooks react-native compatibility how does it work

💡 Result:

preact/hooks is Preact’s own hooks implementation, and it only works when your component tree is being rendered by Preact’s renderer (either directly via preact or via the React-compat layer preact/compat). It is not React’s hooks package. [1]

How “React compatibility” works (where it does work)

Preact’s React ecosystem support is primarily done by mapping React’s public API surface to Preact using preact/compat (e.g., import React from "react" can be redirected to preact/compat). This is typically done by aliasing/redirecting module resolution so packages that import react/react-dom get Preact instead. [2][1]

A common “official-ish” way to do that today is npm aliasing:

  • install react as @preact/compat
  • install react-dom as @preact/compat
    so react / react-dom resolve to Preact’s compat layer. [2]

Don’t mix hook implementations

If some code imports hooks from preact/hooks while other code (or dependencies) import hooks from react (which you aliased to preact/compat), you can end up with two different hook singletons and get hard-to-debug runtime errors. The practical rule: pick one import style consistently across your app and dependencies. [3]

Why this usually doesn’t work for React Native (iOS/Android)

React Native is not “React DOM”; it uses a different renderer (react-native) with its own internals and expectations. Simply aliasing react to preact/compat doesn’t give you a compatible React Native renderer, so it’s not supported out-of-the-box. [4]

If you want Preact-like size/perf in a “React Native app,” the common approaches are:

  • Use React Native Web on the web side (it explicitly notes Preact can be supported there), because that path ultimately renders to the web/DOM toolchain. [5]
  • Or embed a web app (React/Preact) in a WebView rather than trying to replace React inside the native renderer. [4]

Sources: Preact compat/differences docs [1], @preact/compat alias package instructions [2], report on hook-implementation mismatch [3], React Native not supported out of the box [4], React Native Web rendering notes (mentions Preact support) [5].


🏁 Script executed:

# Check if there are any other references to Preact + React Native in the codebase
rg -i "preact.*react-native|react-native.*preact" --type md

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Look at the Preact documentation structure to understand if React Native is a supported target
fd -t f "README.md" -path "*/preact/*" --exec head -50 {}

Repository: TanStack/form

Length of output: 225


🏁 Script executed:

# Check Preact/compat documentation or examples related to React Native
fd -t f "compat*" -path "*/preact/*" --exec cat {} \;

Repository: TanStack/form

Length of output: 225


🏁 Script executed:

# Search for React Native in TanStack Form preact documentation
rg -i "react.native" docs/framework/preact/ -A 3 -B 3

Repository: TanStack/form

Length of output: 1160


🏁 Script executed:

# Check if there's any special setup or adapter code for React Native
fd -t f "preact" --exec grep -l "react-native" {} \;

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Look for any configuration or setup guide mentioning React Native + Preact
fd -t f "*.md" docs/ --exec grep -l "react-native.*preact\|preact.*react-native" {} \;

Repository: TanStack/form

Length of output: 340


🌐 Web query:

TanStack Form Preact React Native support documentation

💡 Result:

React Native support (TanStack Form)

TanStack Form’s React adapter documents React Native usage and says it “should support React Native out-of-the-box” (no special config), with examples using TextInput/onChangeText. [1]

Preact support (TanStack Form)

TanStack Form’s official “Supported Frameworks” list includes React, Vue, Angular, Solid, Lit, Sveltenot Preact. It also invites the community to create additional adapters. [2]

There was work on a Preact adapter in the TanStack/form repo (PR “PREACT ADAPTER: update all react tooling and use preact instead”), but that PR was closed (Mar 31, 2026) rather than merged. [3]

Sources:
[1] TanStack Form React docs – “Usage with React Native”
[2] TanStack Form docs – “Supported TanStack Form Frameworks”
[3] TanStack/form GitHub – PR #1880 (“PREACT ADAPTER…”)


🏁 Script executed:

# Check package.json for Preact presence
cat package.json | head -100

Repository: TanStack/form

Length of output: 2831


🏁 Script executed:

# Look for supported frameworks documentation in the repo
fd -t f "supported\|frameworks\|getting-started" docs/ | head -20

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Check the main docs structure
ls -la docs/

Repository: TanStack/form

Length of output: 814


🏁 Script executed:

# Search for any references to Preact adapter status or warnings
rg -i "preact.*(experimental|unsupported|closed|deprecated|adapter)" --type md

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Check the docs config to see if Preact is listed
cat docs/config.json | jq '.'

Repository: TanStack/form

Length of output: 22463


🏁 Script executed:

# Look for framework list in overview or installation docs
rg -i "supported.*framework|framework.*support" docs/ -A 5 -B 5

Repository: TanStack/form

Length of output: 2696


🏁 Script executed:

# Check if there's any disclaimer about Preact being unsupported
rg -i "preact" docs/ --type md | head -30

Repository: TanStack/form

Length of output: 3677


🌐 Web query:

TanStack Form Preact adapter status 2026 official support

💡 Result:

As of March 31, 2026, TanStack Form does not have an official Preact adapter. The official “Supported TanStack Form Frameworks” list includes React, Vue, Angular, Solid, Lit, and Svelte—but not Preact. (tanstack.com)

There was a “PREACT ADAPTER” pull request (#1880) proposing Preact support, but it was closed on March 31, 2026 (not merged), so it did not become officially supported. (github.com)

Citations:


Remove React Native section or add critical disclaimer—Preact is not officially supported and the React Native example is non-functional.

Preact is not in TanStack Form's official supported frameworks list (React, Vue, Angular, Solid, Lit, Svelte). The Preact adapter PR was closed without merging (March 31, 2026). The "React Native (via compat)" section is particularly problematic: preact/compat provides DOM API compatibility only and does not work with React Native's renderer. Using preact/hooks with react-native components will not function as documented. Either remove this section entirely, or add a clear warning that Preact and React Native integration is unsupported and non-functional.

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

In `@docs/framework/preact/guides/focus-management.md` around lines 71 - 141,
Update the "React Native (via compat)" section in focus-management.md: either
remove the entire React Native example (the App component and its imports:
useRef from 'preact/hooks', TextInput, View, Text, Button, Alert from
'react-native', and useForm from '@tanstack/preact-form') or replace it with a
prominent warning stating that Preact is not officially supported by TanStack
Form (not listed among React/Vue/Angular/Solid/Lit/Svelte), the Preact adapter
PR was closed, and that using preact/compat or preact/hooks with react-native
components is unsupported and non-functional; ensure the warning appears before
any example and references "React Native (via compat)" and the App/example
snippet so readers cannot mistake it for a working integration.


# Interface: WithFieldGroupProps\<TFieldGroupData, TFieldComponents, TFormComponents, TSubmitMeta, TRenderProps\>

Defined in: [packages/react-form/src/createFormHook.tsx:256](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L256)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify that the Preact package has the corresponding source file

# Check if the preact-form package has createFormHook.tsx
fd -t f 'createFormHook.tsx' packages/preact-form/

# Also verify the interface exists in the Preact implementation
rg -n "interface WithFieldGroupProps" packages/preact-form/ -A 2

Repository: TanStack/form

Length of output: 364


🏁 Script executed:

# Check the documentation file to see all the "Defined in:" references
cat docs/framework/preact/reference/interfaces/WithFieldGroupProps.md | head -60 | cat -n

Repository: TanStack/form

Length of output: 1688


🏁 Script executed:

# Get the lines around 257, 264, and 265 in the Preact file to understand what they define
sed -n '255,266p' packages/preact-form/src/createFormHook.tsx | cat -n

Repository: TanStack/form

Length of output: 578


🏁 Script executed:

# Check what the React version has at similar lines for comparison
rg -n "interface WithFieldGroupProps" packages/react-form/src/ -A 2

Repository: TanStack/form

Length of output: 317


Fix incorrect source file references in Preact documentation.

This documentation file for Preact references packages/react-form/src/createFormHook.tsx instead of the correct packages/preact-form/src/createFormHook.tsx. Update the "Defined in:" links on lines 8, 44, and 54 to point to the Preact implementation.

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

In `@docs/framework/preact/reference/interfaces/WithFieldGroupProps.md` at line 8,
The "Defined in:" links in
docs/framework/preact/reference/interfaces/WithFieldGroupProps.md incorrectly
point to the React implementation; update the three links (currently referencing
packages/react-form/src/createFormHook.tsx) to reference the Preact
implementation at packages/preact-form/src/createFormHook.tsx so the
documentation for WithFieldGroupProps correctly links to the Preact source
(adjust the links on the lines that show "Defined in:" and any other occurrences
that reference createFormHook.tsx).

}) => ReturnType<FunctionComponent>;
```

Defined in: [packages/react-form/src/useField.tsx:523](https://github.com/TanStack/form/blob/main/packages/react-form/src/useField.tsx#L523)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify that the Preact package has the corresponding source file

# Check if the preact-form package has useField.tsx
fd -t f 'useField.tsx' packages/preact-form/

# Verify the type alias exists in the Preact implementation
rg -n "type FieldComponent" packages/preact-form/ -A 2

Repository: TanStack/form

Length of output: 343


Incorrect source file reference for Preact documentation.

The "Defined in:" link on line 15 references packages/react-form/src/useField.tsx:523, but this is Preact documentation and should reference packages/preact-form/src/useField.tsx:521 instead.

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

In `@docs/framework/preact/reference/type-aliases/FieldComponent.md` at line 15,
In docs/framework/preact/reference/type-aliases/FieldComponent.md update the
"Defined in:" link so it points to the Preact implementation of useField (the
preact-form useField.tsx source) instead of the React implementation; replace
the react-form reference with the package that contains the Preact useField
definition so the link resolves to the correct Preact source location.

Comment on lines +1 to +14
---
id: ReactFormExtendedApi
title: ReactFormExtendedApi
---

# Type Alias: ReactFormExtendedApi\<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta\>

```ts
type ReactFormExtendedApi<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta> = FormApi<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta> & ReactFormApi<TFormData, TOnMount, TOnChange, TOnChangeAsync, TOnBlur, TOnBlurAsync, TOnSubmit, TOnSubmitAsync, TOnDynamic, TOnDynamicAsync, TOnServer, TSubmitMeta>;
```

Defined in: [packages/react-form/src/useForm.tsx:99](https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx#L99)

An extended version of the `FormApi` class that includes React-specific functionalities from `ReactFormApi`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Documentation incorrectly references React instead of Preact.

This documentation file for the Preact package incorrectly references React throughout:

  • The type alias is named ReactFormExtendedApi instead of PreactFormExtendedApi
  • The source definition points to packages/react-form/src/useForm.tsx instead of packages/preact-form/src/useForm.tsx
  • The description mentions "React-specific functionalities"

This appears to be a copy-paste from the React documentation that wasn't updated for Preact. Should either be renamed to use Preact-specific naming or, if the Preact package intentionally reuses React type names for API consistency, the source path and description should still be corrected.

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

In `@docs/framework/preact/reference/type-aliases/ReactFormExtendedApi.md` around
lines 1 - 14, The docs incorrectly reference React; update the type alias and
metadata to Preact equivalents: rename ReactFormExtendedApi to
PreactFormExtendedApi in this doc, update the source link to
packages/preact-form/src/useForm.tsx (and confirm the definition in
useForm.tsx), and change the description text to mention Preact-specific
functionalities (or explicitly note that the Preact package reuses ReactFormApi
naming if that is intentional). Ensure references to ReactFormApi/FormApi remain
accurate or are renamed to PreactFormApi/FormApi to match the actual exported
types in the preact package.

Comment on lines +23 to +25
// We should never hit the `null` case here
const FieldContext = createContext<AnyFieldApi>(null as never)
const FormContext = createContext<AnyFormApi>(null as never)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the file
find . -path "*packages/preact-form/src/createFormHook.tsx" -type f

Repository: TanStack/form

Length of output: 102


🏁 Script executed:

# Let's view the entire file to understand the structure
cat -n packages/preact-form/src/createFormHook.tsx

Repository: TanStack/form

Length of output: 21514


createFormHookContexts() and useTypedAppFormContext() break context isolation between independent hook instances.

FieldContext and FormContext are created once at module scope (lines 23–25). Each call to createFormHookContexts() returns references to these shared singletons, not isolated instances. Additionally, useTypedAppFormContext() (line 592) ignores the formContext parameter passed to createFormHook() and reads from the module-scoped FormContext instead. This prevents proper isolation when creating multiple independent form systems with separate contexts.

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

In `@packages/preact-form/src/createFormHook.tsx` around lines 23 - 25, The
module-scoped FieldContext and FormContext singletons break isolation: instead,
create new contexts inside createFormHookContexts() (call
createContext<AnyFieldApi>() and createContext<AnyFormApi>() there) and return
those instances so each hook system gets its own contexts; then update
useTypedAppFormContext to accept or close over the form context returned from
createFormHookContexts() (stop reading the module-scoped FormContext) so it uses
the instance-specific FormContext/FieldContext. Ensure all references to the
former module-scoped FieldContext/FormContext (and any functions that call
useTypedAppFormContext) are updated to use the contexts returned by
createFormHookContexts().

Comment on lines +433 to +445
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnMount>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChange>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChangeAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlur>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlurAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmit>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmitAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamic>,
UnwrapDefaultOrAny<
undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync
>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnServer>,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

head -n 450 packages/preact-form/src/createFormHook.tsx | tail -n 30

Repository: TanStack/form

Length of output: 1217


🏁 Script executed:

rg "FormValidateOrFn|FormAsyncValidateOrFn" packages/preact-form/src/ -A 3

Repository: TanStack/form

Length of output: 31003


🏁 Script executed:

rg "UnwrapDefaultOrAny" packages/preact-form/src/ -B 2 -A 5

Repository: TanStack/form

Length of output: 2447


Use FormAsyncValidateOrFn for async validator slots in type narrowing.

The UnwrapDefaultOrAny branches for TOnChangeAsync, TOnBlurAsync, TOnSubmitAsync, TOnDynamicAsync, and TOnServer must use FormAsyncValidateOrFn instead of FormValidateOrFn to match their actual type parameter defaults. Currently, the mismatch prevents UnwrapDefaultOrAny from detecting when these generics use their defaults, causing improper type narrowing in withForm.

Fix
-    UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChangeAsync>,
+    UnwrapDefaultOrAny<
+      undefined | FormAsyncValidateOrFn<TFormData>,
+      TOnChangeAsync
+    >,
@@
-    UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlurAsync>,
+    UnwrapDefaultOrAny<
+      undefined | FormAsyncValidateOrFn<TFormData>,
+      TOnBlurAsync
+    >,
@@
-    UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmitAsync>,
+    UnwrapDefaultOrAny<
+      undefined | FormAsyncValidateOrFn<TFormData>,
+      TOnSubmitAsync
+    >,
@@
-    UnwrapDefaultOrAny<
-      undefined | FormValidateOrFn<TFormData>,
-      TOnDynamicAsync
-    >,
-    UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnServer>,
+    UnwrapDefaultOrAny<
+      undefined | FormAsyncValidateOrFn<TFormData>,
+      TOnDynamicAsync
+    >,
+    UnwrapDefaultOrAny<
+      undefined | FormAsyncValidateOrFn<TFormData>,
+      TOnServer
+    >,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnMount>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChange>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChangeAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlur>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlurAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmit>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmitAsync>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamic>,
UnwrapDefaultOrAny<
undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync
>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnServer>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnMount>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChange>,
UnwrapDefaultOrAny<
undefined | FormAsyncValidateOrFn<TFormData>,
TOnChangeAsync
>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlur>,
UnwrapDefaultOrAny<
undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlurAsync
>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmit>,
UnwrapDefaultOrAny<
undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmitAsync
>,
UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamic>,
UnwrapDefaultOrAny<
undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamicAsync
>,
UnwrapDefaultOrAny<
undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer
>,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/src/createFormHook.tsx` around lines 433 - 445, The
type-narrowing mismatch is caused by using FormValidateOrFn for async validator
slots; update the UnwrapDefaultOrAny generic instantiations for TOnChangeAsync,
TOnBlurAsync, TOnSubmitAsync, TOnDynamicAsync and TOnServer to use
FormAsyncValidateOrFn (instead of FormValidateOrFn) so the default-detection
logic in UnwrapDefaultOrAny correctly recognizes the async defaults used by
withForm; touch the occurrences in createFormHook.tsx where UnwrapDefaultOrAny
is invoked with these TOn*Async type parameters.

Comment on lines +188 to +211
const [prevFormId, setPrevFormId] = useState<string>(opts?.formId as never)

const [formApi, setFormApi] = useState(() => {
return new FormApi<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>({ ...opts, formId: opts?.formId ?? fallbackFormId })
})

if (prevFormId !== opts?.formId) {
const formId = opts?.formId ?? fallbackFormId
setFormApi(new FormApi({ ...opts, formId }))
setPrevFormId(formId)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Swapping FormApi on formId change leaves the replacement instance unmounted.

When formId changes after the first commit, Lines 207-211 replace formApi, but Line 258 only mounts the original instance because the effect is pinned to []. The new FormApi never gets mount(), and the old one stays mounted until unmount. Please key the lifecycle off the current instance/resolved formId instead of replacing it only in render.

Also applies to: 258-258

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

In `@packages/preact-form/src/useForm.tsx` around lines 188 - 211, The current
render-time replacement of formApi (via setFormApi and setPrevFormId) can create
an instance that never receives mount() because the mounting effect is pinned to
[] — instead resolve the current formId (opts?.formId ?? fallbackFormId) and
move creation/teardown of FormApi into a useEffect that depends on that resolved
formId (and/or the formApi instance) so the effect will call new FormApi(...),
call mount() on the new instance, and unmount() the previous instance; update
references to prevFormId/setPrevFormId to no longer swap instances in render and
ensure FormApi lifecycle is keyed by the resolved formId and the formApi
instance.

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: 4

♻️ Duplicate comments (1)
packages/preact-form/src/useForm.tsx (1)

187-211: ⚠️ Potential issue | 🔴 Critical

Resolve formId once before comparing or mounting the FormApi.

prevFormId is updated with the resolved id, but the guard compares it to raw opts?.formId. If a caller goes from "custom-id" back to undefined, the check stays true forever (fallbackId !== undefined), so render keeps creating new FormApi instances; and with Line 258 pinned to [], replacements still never get mount().

💡 Minimal fix
   const fallbackFormId = useFormId()
-  const [prevFormId, setPrevFormId] = useState<string>(opts?.formId as never)
+  const resolvedFormId = opts?.formId ?? fallbackFormId
+  const [prevFormId, setPrevFormId] = useState<string>(resolvedFormId)

   const [formApi, setFormApi] = useState(() => {
-    return new FormApi<
-      TFormData,
-      TOnMount,
-      TOnChange,
-      TOnChangeAsync,
-      TOnBlur,
-      TOnBlurAsync,
-      TOnSubmit,
-      TOnSubmitAsync,
-      TOnDynamic,
-      TOnDynamicAsync,
-      TOnServer,
-      TSubmitMeta
-    >({ ...opts, formId: opts?.formId ?? fallbackFormId })
+    return new FormApi<
+      TFormData,
+      TOnMount,
+      TOnChange,
+      TOnChangeAsync,
+      TOnBlur,
+      TOnBlurAsync,
+      TOnSubmit,
+      TOnSubmitAsync,
+      TOnDynamic,
+      TOnDynamicAsync,
+      TOnServer,
+      TSubmitMeta
+    >({ ...opts, formId: resolvedFormId })
   })

-  if (prevFormId !== opts?.formId) {
-    const formId = opts?.formId ?? fallbackFormId
-    setFormApi(new FormApi({ ...opts, formId }))
-    setPrevFormId(formId)
+  if (prevFormId !== resolvedFormId) {
+    setFormApi(new FormApi({ ...opts, formId: resolvedFormId }))
+    setPrevFormId(resolvedFormId)
   }
…
-  useIsomorphicLayoutEffect(formApi.mount, [])
+  useIsomorphicLayoutEffect(formApi.mount, [formApi])

Also applies to: 258-258

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

In `@packages/preact-form/src/useForm.tsx` around lines 187 - 211, Resolve the
effective formId once (const resolvedFormId = opts?.formId ?? fallbackFormId)
and use that when initializing FormApi and when comparing/updating prevFormId;
initialize prevFormId to resolvedFormId (not raw opts?.formId), compare
prevFormId !== resolvedFormId before creating a new FormApi, call setFormApi(new
FormApi({ ...opts, formId: resolvedFormId })) and then
setPrevFormId(resolvedFormId) so switching between a custom id and undefined
(which falls back) won’t endlessly recreate FormApi or block mount().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/framework/angular/guides/dynamic-validation.md`:
- Around line 13-17: These Angular documentation formatting edits (changes to
imports like TanStackField, injectForm, revalidateLogic in the dynamic
validation docs) are unrelated to the Preact integration PR—remove or revert
these formatting-only changes from this branch and instead place them in a
separate doc/formatting PR; specifically undo the modified import formatting and
any other changes around the same import blocks (also at the other noted
regions) so the current PR only contains Preact integration code.
- Line 23: The placeholder template strings (e.g., the property template: ` <!--
Your form template here --> `) removed the real Angular form examples; restore
the original working template HTML wherever those placeholders appear (including
occurrences at the three other spots referenced) by replacing the placeholder
string with the original form markup used elsewhere in the doc (copy the
concrete template examples from the retained examples around the other sections
such as the form controls and validation message snippets) so each example
includes full, runnable template code; update the same template property
name/variable where it was replaced to ensure consistency across examples.

In `@packages/preact-form/src/useField.tsx`:
- Around line 34-49: The Field member on the field API is currently assigned the
unbound root Field component; instead bind and expose a wrapper that injects the
current field's form context so consumers can call fieldApi.Field(...) without
manually providing form. Replace the direct assignment of the root Field with a
bound component factory that captures the parent form (the same form used by
useField) and renders the root Field passing form plus any incoming props;
reference the Field symbol, the fieldApi.Field member, and the useField call in
the root Field component to ensure the wrapper forwards form to useField.

In `@packages/preact-form/src/useFieldGroup.tsx`:
- Around line 169-254: useFieldGroup currently creates formLensApi once and
never syncs it with changing inputs; add an update path so wrappers
(extendedApi.AppField, Field, Subscribe) don't hold stale refs. Fix by either
adding an update(opts) method to FieldGroupApi (matching FieldApi/FormApi) and
calling formLensApi.update(opts) on each render (or inside a useEffect) to
propagate changes to opts.form, opts.fields, opts.defaultValues,
opts.onSubmitMeta, and opts.formComponents, or recreate the FieldGroupApi
instance when those specific binding inputs change (replace the useState factory
with a keyed memo/rehydration that re-instantiates FieldGroupApi when
opts.form/fields/defaultValues/onSubmitMeta/formComponents change); ensure the
same extendedApi properties (AppField/AppForm/Field/Subscribe) continue to
reference the updated internal form instance.

---

Duplicate comments:
In `@packages/preact-form/src/useForm.tsx`:
- Around line 187-211: Resolve the effective formId once (const resolvedFormId =
opts?.formId ?? fallbackFormId) and use that when initializing FormApi and when
comparing/updating prevFormId; initialize prevFormId to resolvedFormId (not raw
opts?.formId), compare prevFormId !== resolvedFormId before creating a new
FormApi, call setFormApi(new FormApi({ ...opts, formId: resolvedFormId })) and
then setPrevFormId(resolvedFormId) so switching between a custom id and
undefined (which falls back) won’t endlessly recreate FormApi or block mount().
🪄 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: 4d4bcb03-a51f-410d-bcfe-8db67e5142cc

📥 Commits

Reviewing files that changed from the base of the PR and between b8189a9 and 0e39f14.

📒 Files selected for processing (15)
  • docs/framework/angular/guides/arrays.md
  • docs/framework/angular/guides/basic-concepts.md
  • docs/framework/angular/guides/dynamic-validation.md
  • docs/framework/angular/guides/form-composition.md
  • docs/framework/angular/guides/listeners.md
  • docs/framework/angular/guides/submission-handling.md
  • docs/framework/angular/guides/validation.md
  • docs/framework/angular/quick-start.md
  • packages/preact-form/src/index.ts
  • packages/preact-form/src/useField.tsx
  • packages/preact-form/src/useFieldGroup.tsx
  • packages/preact-form/src/useForm.tsx
  • packages/preact-form/src/useStore.ts
  • packages/preact-form/tests/useField.test.tsx
  • packages/preact-form/tests/useForm.test.tsx
✅ Files skipped from review due to trivial changes (9)
  • docs/framework/angular/guides/listeners.md
  • docs/framework/angular/quick-start.md
  • docs/framework/angular/guides/form-composition.md
  • docs/framework/angular/guides/basic-concepts.md
  • docs/framework/angular/guides/submission-handling.md
  • docs/framework/angular/guides/arrays.md
  • packages/preact-form/src/index.ts
  • docs/framework/angular/guides/validation.md
  • packages/preact-form/tests/useField.test.tsx

Comment on lines +13 to +17
import {
TanStackField,
injectForm,
revalidateLogic,
} from '@tanstack/angular-form'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These Angular documentation formatting changes are unrelated to the PR objective.

This PR is about adding Preact integration, but these changes modify Angular documentation formatting. Consider moving unrelated documentation formatting updates to a separate PR to maintain clear change scope and simplify review.

Also applies to: 90-95, 127-132, 178-182, 244-248, 283-287

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

In `@docs/framework/angular/guides/dynamic-validation.md` around lines 13 - 17,
These Angular documentation formatting edits (changes to imports like
TanStackField, injectForm, revalidateLogic in the dynamic validation docs) are
unrelated to the Preact integration PR—remove or revert these formatting-only
changes from this branch and instead place them in a separate doc/formatting PR;
specifically undo the modified import formatting and any other changes around
the same import blocks (also at the other noted regions) so the current PR only
contains Preact integration code.

template: `
<!-- Your form template here -->
`,
template: ` <!-- Your form template here --> `,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Documentation regression: Template examples replaced with non-functional placeholders.

Replacing actual template code with placeholder comments like <!-- Your form template here --> significantly reduces the educational value of this guide. Users rely on complete, working examples to understand how to implement dynamic validation.

Additionally, this is inconsistent—some examples (e.g., lines 101, 138-143, 189-213) retain actual template code while these are replaced with placeholders.

Restore the original template examples to maintain documentation quality.

Also applies to: 70-70, 254-254, 294-294

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

In `@docs/framework/angular/guides/dynamic-validation.md` at line 23, The
placeholder template strings (e.g., the property template: ` <!-- Your form
template here --> `) removed the real Angular form examples; restore the
original working template HTML wherever those placeholders appear (including
occurrences at the three other spots referenced) by replacing the placeholder
string with the original form markup used elsewhere in the doc (copy the
concrete template examples from the retained examples around the other sections
such as the form controls and validation message snippets) so each example
includes full, runnable template code; update the same template property
name/variable where it was replaced to ensure consistency across examples.

Comment on lines +34 to +49
* A pre-bound and type-safe sub-field component using this field as a root.
*/
Field: FieldComponent<
TParentData,
TFormOnMount,
TFormOnChange,
TFormOnChangeAsync,
TFormOnBlur,
TFormOnBlurAsync,
TFormOnSubmit,
TFormOnSubmitAsync,
TFormOnDynamic,
TFormOnDynamicAsync,
TFormOnServer,
TPatentSubmitMeta
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd packages/preact-form && wc -l src/useField.tsx

Repository: TanStack/form

Length of output: 77


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '30,55p'

Repository: TanStack/form

Length of output: 945


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '315,330p'

Repository: TanStack/form

Length of output: 512


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '715,750p'

Repository: TanStack/form

Length of output: 1113


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '200,230p'

Repository: TanStack/form

Length of output: 1237


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '280,325p'

Repository: TanStack/form

Length of output: 1314


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '240,280p'

Repository: TanStack/form

Length of output: 1764


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '150,180p'

Repository: TanStack/form

Length of output: 1542


🏁 Script executed:

rg "fieldApi\.Field|field\.Field" packages/preact-form --type ts --type tsx -B 2 -A 2

Repository: TanStack/form

Length of output: 84


🏁 Script executed:

grep -r "pre-bound" packages/preact-form --include="*.ts" --include="*.tsx" -B 2 -A 2

Repository: TanStack/form

Length of output: 366


🏁 Script executed:

rg "fieldApi\.Field|field\.Field" packages/preact-form -B 2 -A 2

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

find packages/preact-form -name "*.test.*" -o -name "*.spec.*" | head -5

Repository: TanStack/form

Length of output: 196


🏁 Script executed:

grep -n "\.Field" packages/preact-form/tests/useField.test.tsx -B 2 -A 2

Repository: TanStack/form

Length of output: 7833


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '690,750p'

Repository: TanStack/form

Length of output: 2629


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '85,110p'

Repository: TanStack/form

Length of output: 774


🏁 Script executed:

grep -n "opts\." packages/preact-form/src/useField.tsx | head -20

Repository: TanStack/form

Length of output: 378


🏁 Script executed:

grep -n "field\.Field\|fieldApi\.Field" packages/preact-form/tests/ -r

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '1,50p'

Repository: TanStack/form

Length of output: 2119


🏁 Script executed:

grep -n "UseFieldOptions\|UseFieldOptionsBound" packages/preact-form/src/types.ts -A 10 | head -40

Repository: TanStack/form

Length of output: 1104


🏁 Script executed:

cat -n packages/preact-form/src/types.ts | sed -n '1,100p'

Repository: TanStack/form

Length of output: 4114


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '82,135p'

Repository: TanStack/form

Length of output: 1563


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '61,75p'

Repository: TanStack/form

Length of output: 1033


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '136,200p'

Repository: TanStack/form

Length of output: 2806


🏁 Script executed:

grep -n "form\?" packages/preact-form/src/types.ts | head -20

Repository: TanStack/form

Length of output: 88


🏁 Script executed:

rg "interface UseFieldOptions" packages/preact-form/src/types.ts -A 25

Repository: TanStack/form

Length of output: 2304


🏁 Script executed:

cat -n packages/preact-form/src/types.ts | sed -n '82,130p'

Repository: TanStack/form

Length of output: 1800


🏁 Script executed:

cat -n packages/preact-form/tests/useField.test.tsx | sed -n '520,560p'

Repository: TanStack/form

Length of output: 1996


🏁 Script executed:

python3 << 'EOF'
# Look at the test to understand the pattern
with open('packages/preact-form/tests/useField.test.tsx', 'r') as f:
    content = f.read()
    # Find usage of field.Field (nested field)
    if 'field.Field' in content:
        print("Found field.Field usage in tests")
        # Extract context
        idx = content.find('field.Field')
        print(content[max(0, idx-200):idx+300])
    else:
        print("No field.Field usage found in tests")
EOF

Repository: TanStack/form

Length of output: 92


🏁 Script executed:

cat -n packages/preact-form/src/useField.tsx | sed -n '256,325p'

Repository: TanStack/form

Length of output: 2475


Bind fieldApi.Field instead of aliasing the unbound Field component.

The contract (line 34) documents this member as "pre-bound," but line 322 directly assigns the unbound root Field component. When users call <fieldApi.Field name="subfield">, it reaches the root component at line 746 which immediately calls useField(fieldOptions as any) without the parent field's form context. Since consumers wouldn't know to manually inject form, this breaks the API contract.

Suggested fix

Wrap the component to inject the bound form:

-    extendedApi.Field = Field as never
+    extendedApi.Field = function BoundField(props) {
+      return <Field {...(props as any)} form={opts.form} />
+    } as never
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* A pre-bound and type-safe sub-field component using this field as a root.
*/
Field: FieldComponent<
TParentData,
TFormOnMount,
TFormOnChange,
TFormOnChangeAsync,
TFormOnBlur,
TFormOnBlurAsync,
TFormOnSubmit,
TFormOnSubmitAsync,
TFormOnDynamic,
TFormOnDynamicAsync,
TFormOnServer,
TPatentSubmitMeta
>
extendedApi.Field = function BoundField(props) {
return <Field {...(props as any)} form={opts.form} />
} as never
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/preact-form/src/useField.tsx` around lines 34 - 49, The Field member
on the field API is currently assigned the unbound root Field component; instead
bind and expose a wrapper that injects the current field's form context so
consumers can call fieldApi.Field(...) without manually providing form. Replace
the direct assignment of the root Field with a bound component factory that
captures the parent form (the same form used by useField) and renders the root
Field passing form plus any incoming props; reference the Field symbol, the
fieldApi.Field member, and the useField call in the root Field component to
ensure the wrapper forwards form to useField.

Comment on lines +169 to +254
const [formLensApi] = useState(() => {
const api = new FieldGroupApi(opts)
const form =
opts.form instanceof FieldGroupApi
? (opts.form.form as AppFieldExtendedReactFormApi<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta,
TComponents,
TFormComponents
>)
: opts.form

const extendedApi: AppFieldExtendedReactFieldGroupApi<
TFormData,
TFieldGroupData,
TFields,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta,
TComponents,
TFormComponents
> = api as never

extendedApi.AppForm = function AppForm(appFormProps) {
return <form.AppForm {...appFormProps} />
}

extendedApi.AppField = function AppField(props) {
return (
<form.AppField {...(formLensApi.getFormFieldOptions(props) as any)} />
)
}

extendedApi.Field = function Field(props) {
return <form.Field {...(formLensApi.getFormFieldOptions(props) as any)} />
}

extendedApi.Subscribe = function Subscribe(props: any) {
return (
<LocalSubscribe
lens={formLensApi}
selector={props.selector}
children={props.children}
/>
)
}

return Object.assign(extendedApi, {
...opts.formComponents,
}) as AppFieldExtendedReactFieldGroupApi<
TFormData,
TFieldGroupData,
TFields,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta,
TComponents,
TFormComponents
>
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's see the full useFieldGroup implementation
wc -l packages/preact-form/src/useFieldGroup.tsx

Repository: TanStack/form

Length of output: 103


🏁 Script executed:

# Read the full useFieldGroup file to understand the context
cat -n packages/preact-form/src/useFieldGroup.tsx

Repository: TanStack/form

Length of output: 9273


🏁 Script executed:

# Search for useField and useForm patterns to compare
fd -e tsx -e ts packages/preact-form/src | grep -E "(useField|useForm)" | head -20

Repository: TanStack/form

Length of output: 458


🏁 Script executed:

# Look for FieldGroupApi implementation to understand if it has update methods
fd -e tsx -e ts packages/preact-form/src | xargs grep -l "class FieldGroupApi\|export.*FieldGroupApi" | head -5

Repository: TanStack/form

Length of output: 458


🏁 Script executed:

# Find useField and useForm implementations for comparison
fd . 'packages/preact-form/src' | grep -E "(useField|useForm)" | head -20

Repository: TanStack/form

Length of output: 212


🏁 Script executed:

# Search for FieldGroupApi definition in form-core
fd . 'packages/form-core' | grep -E "(FieldGroupApi|field-group)" | head -20

Repository: TanStack/form

Length of output: 192


🏁 Script executed:

# Check the FieldGroupApi class implementation
rg "class FieldGroupApi|export.*class.*FieldGroupApi" -A 30 packages/form-core/src

Repository: TanStack/form

Length of output: 2550


🏁 Script executed:

# Get the full FieldGroupApi implementation
cat -n packages/form-core/src/FieldGroupApi.ts | head -150

Repository: TanStack/form

Length of output: 5135


🏁 Script executed:

# Look for mount, update, or refresh methods in FieldGroupApi
rg "mount|update|refresh" packages/form-core/src/FieldGroupApi.ts | head -30

Repository: TanStack/form

Length of output: 354


🏁 Script executed:

# Read useField implementation for comparison
cat -n packages/preact-form/src/useField.tsx | head -100

Repository: TanStack/form

Length of output: 4523


🏁 Script executed:

# Read useForm implementation for comparison
cat -n packages/preact-form/src/useForm.tsx | head -100

Repository: TanStack/form

Length of output: 3909


🏁 Script executed:

# Check useField full implementation to see dependency handling
wc -l packages/preact-form/src/useField.tsx

Repository: TanStack/form

Length of output: 98


🏁 Script executed:

# Look for the useMemo and dependency handling in useField
rg "useMemo|useState|useIsomorphicLayoutEffect" packages/preact-form/src/useField.tsx -B 2 -A 5 | head -80

Repository: TanStack/form

Length of output: 1589


🏁 Script executed:

# Check useForm full implementation to see how it handles dependency updates
wc -l packages/preact-form/src/useForm.tsx

Repository: TanStack/form

Length of output: 97


🏁 Script executed:

# Look for dependency arrays in useForm
rg "useMemo|useState|useIsomorphicLayoutEffect" packages/preact-form/src/useForm.tsx -B 2 -A 5 | head -100

Repository: TanStack/form

Length of output: 1486


🏁 Script executed:

# Look at FieldGroupApi constructor to see what it stores
rg "constructor" packages/form-core/src/FieldGroupApi.ts -A 30 | head -60

Repository: TanStack/form

Length of output: 926


🏁 Script executed:

# Verify FieldGroupApi has an update method
rg "update\(" packages/form-core/src/FieldGroupApi.ts -B 2 -A 8 | head -40

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Check the full mount method and any other relevant methods
rg "mount\(\)|update\(" packages/form-core/src/FieldGroupApi.ts -B 1 -A 5

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Get the entire FieldGroupApi.ts file to see all methods
cat -n packages/form-core/src/FieldGroupApi.ts | tail -150

Repository: TanStack/form

Length of output: 5029


🏁 Script executed:

# Search for all methods in FieldGroupApi
rg "^\s+(mount|update|getFormFieldName|getFormFieldOptions)" packages/form-core/src/FieldGroupApi.ts -A 3

Repository: TanStack/form

Length of output: 665


🏁 Script executed:

# Look for the method definitions differently
ast-grep --pattern 'class FieldGroupApi { $$$ }' packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Search the entire FieldGroupApi file for "update" method
rg "update\s*=" packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 39


🏁 Script executed:

# Get the line numbers and search for all methods systematically
grep -n "^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=" packages/form-core/src/FieldGroupApi.ts | grep -v "this\." | tail -40

Repository: TanStack/form

Length of output: 1248


🏁 Script executed:

# Look at the complete FieldGroupApi file
wc -l packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 100


🏁 Script executed:

# Get the middle and end sections
sed -n '200,250p' packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 1260


🏁 Script executed:

# Check if there's an update method anywhere in FieldGroupApi
grep -n "update" packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 356


🏁 Script executed:

# Get the complete constructor implementation
sed -n '225,310p' packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 2237


🏁 Script executed:

# Verify the complete file structure - get the last section
tail -30 packages/form-core/src/FieldGroupApi.ts

Repository: TanStack/form

Length of output: 796


Add update mechanism to track prop changes in useFieldGroup.

This hook initializes formLensApi once and never updates it. Unlike useField and useForm which call .update(opts) on every render to stay synchronized with prop changes, useFieldGroup has no update path. If opts.form, opts.fields, opts.defaultValues, opts.onSubmitMeta, or opts.formComponents change after the initial render, the lens and its wrapper components (AppField, Field, Subscribe) will route through stale references.

FieldGroupApi does not expose an update() method. Either add one (matching the FieldApi and FormApi pattern), or recreate the FieldGroupApi when its binding inputs change.

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

In `@packages/preact-form/src/useFieldGroup.tsx` around lines 169 - 254,
useFieldGroup currently creates formLensApi once and never syncs it with
changing inputs; add an update path so wrappers (extendedApi.AppField, Field,
Subscribe) don't hold stale refs. Fix by either adding an update(opts) method to
FieldGroupApi (matching FieldApi/FormApi) and calling formLensApi.update(opts)
on each render (or inside a useEffect) to propagate changes to opts.form,
opts.fields, opts.defaultValues, opts.onSubmitMeta, and opts.formComponents, or
recreate the FieldGroupApi instance when those specific binding inputs change
(replace the useState factory with a keyed memo/rehydration that re-instantiates
FieldGroupApi when opts.form/fields/defaultValues/onSubmitMeta/formComponents
change); ensure the same extendedApi properties
(AppField/AppForm/Field/Subscribe) continue to reference the updated internal
form instance.

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.

4 participants