Skip to content

feat(react-from): extend appform#2106

Merged
harry-whorlow merged 8 commits intomainfrom
extend-appform
Apr 10, 2026
Merged

feat(react-from): extend appform#2106
harry-whorlow merged 8 commits intomainfrom
extend-appform

Conversation

@harry-whorlow
Copy link
Copy Markdown
Contributor

@harry-whorlow harry-whorlow commented Apr 2, 2026

Summary by CodeRabbit

  • New Features

    • Added an extendForm API to create extensible custom forms (merge/override additional field/form components).
  • Examples

    • Added a runnable React composition example app with demo UI, dev/build scripts, tooling configs, and TypeScript setup.
  • Documentation

    • Expanded the form composition guide with an “Extending custom appForm” section, fixed a type-safety example, and added a performance warning about chaining extensions.
  • Tests

    • Added tests validating extension merging, uniqueness checks, override rules, and repeatable extensions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an extendable form hook API (extendForm) to merge component maps with compile-time duplicate-name checks, example app scaffolding and AppForm components demonstrating extension, docs showing extension patterns and a TypeScript warning, and runtime + type-level tests validating merging and chaining.

Changes

Cohort / File(s) Summary
Docs
docs/framework/react/guides/form-composition.md
Fixed mistyped example field name; split import/example into AppFormContext.tsx + AppForm.tsx; added "Extending custom appForm" section with library prebuilt export and downstream ProfileForm.extendForm(...) examples; added TS performance warning about deep chaining.
Example scaffold & config
examples/react/composition/.eslintrc.cjs, examples/react/composition/.gitignore, examples/react/composition/README.md, examples/react/composition/package.json, examples/react/composition/tsconfig.json, examples/react/composition/index.html
Added a Vite + React example project: ESLint config, gitignore, README, package.json, tsconfig, and HTML entrypoint.
Example source
examples/react/composition/src/index.tsx, examples/react/composition/src/AppForm/...
examples/react/composition/src/AppForm/AppForm.tsx, .../FieldComponents/TextField.tsx, .../FormComponents/SubmitButton.tsx
Implemented AppForm context/hook wiring exporting useAppForm and contexts; added TextField and SubmitButton components; added example app demonstrating defaultValues, sync/async validators, submission, and devtools integration.
Core library API
packages/react-form/src/createFormHook.tsx
Added extendForm(extension) to createFormHook return value. It merges fieldComponents/formComponents over the base, returns a new hook that reuses the same contexts, and uses generics to produce compile-time errors for duplicate component names.
Tests
packages/react-form/tests/createFormHook.test-d.tsx, packages/react-form/tests/createFormHook.test.tsx
Added type-level and runtime tests for extendForm: merging of parent+extended components, chaining multiple extensions, withForm compatibility, and @ts-expect-error checks for duplicate names.
Changeset
.changeset/neat-jars-rescue.md
Added a changeset marking a minor release for the new extension method.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Downstream Dev
    participant Base as createFormHook()
    participant Extend as extendForm()
    participant Hook as Extended Hook
    participant App as App (uses hook)

    Dev->>Base: createFormHook({ fieldComponents, formComponents })
    Base-->>Dev: baseHook (useAppForm, contexts, component maps)

    Dev->>Extend: baseHook.extendForm({ fieldComponents?, formComponents? })
    Note over Extend: Merge base + extension\nCompile-time uniqueness checks for overlapping keys
    Extend-->>Dev: extendedHook (reused contexts, merged component maps)

    App->>Hook: useExtendedHook() / render
    Hook-->>App: AppField / form components (parent + extended components available)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I stitched new hooks to fields and forms,
I hopped through docs, examples, tests and norms,
Extend a form, then extend once more,
Merged components open a wider door,
🥕 Hooray — type-safe carrots to explore!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is entirely empty, missing all required template sections including motivation/changes, checklist items, and release impact information. Add a complete pull request description following the template: describe the changes made, confirm testing via 'pnpm test:pr', and document the changeset for this minor version bump.
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% 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 'feat(react-from): extend appform' clearly describes the main change—adding extension capability to AppForm. It's concise and specific, though it contains a typo ('react-from' should be 'react-form').

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch extend-appform

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.

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Apr 2, 2026

View your CI Pipeline Execution ↗ for commit f6733e4

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

☁️ Nx Cloud last updated this comment at 2026-04-10 11:32:38 UTC

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

🚀 Changeset Version Preview

2 package(s) bumped directly, 11 bumped as dependents.

🟨 Minor bumps

Package Version Reason
@tanstack/react-form 1.28.6 → 1.29.0 Changeset
@tanstack/svelte-form 1.28.6 → 1.29.0 Changeset
@tanstack/angular-form 1.28.6 → 1.29.0 Dependent
@tanstack/form-core 1.28.6 → 1.29.0 Dependent
@tanstack/react-form-nextjs 1.28.6 → 1.29.0 Dependent
@tanstack/react-form-remix 1.28.6 → 1.29.0 Dependent
@tanstack/react-form-start 1.28.6 → 1.29.0 Dependent
@tanstack/solid-form 1.28.6 → 1.29.0 Dependent
@tanstack/vue-form 1.28.6 → 1.29.0 Dependent

🟩 Patch bumps

Package Version Reason
@tanstack/form-devtools 0.2.20 → 0.2.21 Dependent
@tanstack/lit-form 1.23.26 → 1.23.27 Dependent
@tanstack/react-form-devtools 0.2.20 → 0.2.21 Dependent
@tanstack/solid-form-devtools 0.2.20 → 0.2.21 Dependent

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 2, 2026

More templates

@tanstack/angular-form

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

@tanstack/form-core

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

@tanstack/form-devtools

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

@tanstack/lit-form

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

@tanstack/react-form

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

@tanstack/react-form-devtools

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

@tanstack/react-form-nextjs

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

@tanstack/react-form-remix

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

@tanstack/react-form-start

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

@tanstack/solid-form

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

@tanstack/solid-form-devtools

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

@tanstack/svelte-form

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

@tanstack/vue-form

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

commit: f6733e4

@sentry
Copy link
Copy Markdown

sentry bot commented Apr 2, 2026

Codecov Report

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

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

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

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

@harry-whorlow harry-whorlow marked this pull request as ready for review April 6, 2026 19:59
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

🧹 Nitpick comments (5)
packages/react-form/tests/createFormHook.test-d.tsx (1)

993-1021: The chaining type test never proves ThirdField survived the second extension.

This case creates ThirdField, but the assertions still only cover Test and ExtendedField, then stop at expectTypeOf(doublyExtendedForm.AppField).toBeFunction(). A regression where the second extendForm drops the new key would still pass.

Suggested fix
-      const { useAppForm: useDoublyExtended } = baseHook
+      const {
+        useAppForm: useDoublyExtended,
+        withForm: withDoublyExtendedForm,
+      } = baseHook
         .extendForm({ fieldComponents: { ExtendedField } })
         .extendForm({ fieldComponents: { ThirdField } })
 
-      withExtendedForm({
+      withDoublyExtendedForm({
         defaultValues: { name: '' },
         render: ({ form }) => {
           return (
             <form.AppField name="name">
               {(field) => {
                 expectTypeOf(field.Test).toBeFunction()
                 expectTypeOf(field.ExtendedField).toBeFunction()
+                expectTypeOf(field.ThirdField).toBeFunction()
                 return null
               }}
             </form.AppField>
           )
         },
       })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/tests/createFormHook.test-d.tsx` around lines 993 - 1021,
The test never asserts that ThirdField survived the second extendForm call;
update the test around useDoublyExtended/withExtendedForm to assert ThirdField
is present — add expectTypeOf(field.ThirdField).toBeFunction() inside the render
callback (alongside the existing Test and ExtendedField checks) and also assert
the doublyExtendedForm exposes the extended field (e.g., an assertion that the
useDoublyExtended result exposes ThirdField on AppField or the equivalent
exported shape) so the chaining regression would fail if the second extension
drops the key.
examples/react/composition/index.html (1)

9-9: Title doesn't match the example name.

The title says "Simple Example App" but this is the composition example. Consider updating to reflect the actual example purpose.

-    <title>TanStack Form React Simple Example App</title>
+    <title>TanStack Form React Composition Example App</title>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/composition/index.html` at line 9, Update the HTML <title>
element to reflect this is the "Composition" example rather than "Simple Example
App": change the title text content inside the <title> tag (currently "TanStack
Form React Simple Example App") to something like "TanStack Form React
Composition Example" so it accurately describes this example page.
examples/react/composition/src/index.tsx (2)

43-48: Async validator returns false instead of undefined when valid.

When value.includes('error') is false, the && short-circuit returns false. While TanStack Form may handle this, explicitly returning undefined for valid state is clearer and more conventional.

             onChangeAsync: async ({ value }) => {
               await new Promise((resolve) => setTimeout(resolve, 1000))
-              return (
-                value.includes('error') && 'No "error" allowed in first name'
-              )
+              return value.includes('error')
+                ? 'No "error" allowed in first name'
+                : undefined
             },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/composition/src/index.tsx` around lines 43 - 48, The async
validator onChangeAsync currently returns the string error when
value.includes('error') is true but returns false when valid due to the &&
expression; update the onChangeAsync implementation (the async validator
function) to explicitly return undefined for valid input instead of false—e.g.,
replace the short-circuit expression with a conditional (ternary or if) that
returns 'No "error" allowed in first name' when value.includes('error') is true
and undefined otherwise.

54-56: Consider using a distinct label for the lastName field.

Both fields currently display "last name". The second one is correct, but you may want to capitalize it consistently (e.g., "Last Name").

-          {(f) => <f.TextField label="last name" />}
+          {(f) => <f.TextField label="Last Name" />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/react/composition/src/index.tsx` around lines 54 - 56, The lastName
field's visible label is not distinct/capitalized; update the form.AppField for
name="lastName" to use a proper, distinct label (e.g., change the f.TextField
label prop to "Last Name") and verify the other field (form.AppField
name="firstName") uses "First Name" so both fields are correctly labeled and
consistently capitalized; look for usages of form.AppField and the f.TextField
label prop to make this change.
examples/react/composition/src/AppForm/AppForm.tsx (1)

16-21: Consider exporting extendForm for downstream composition.

Given this PR introduces form composition capabilities via extendForm, you might want to export it alongside useAppForm so downstream consumers can extend this form with additional components.

-const { useAppForm } = createFormHook({
+const { useAppForm, extendForm } = createFormHook({
   fieldContext,
   formContext,
   fieldComponents: { TextField: TextField },
   formComponents: { SubmitButton },
 })
+
+export { extendForm }

Also, minor: TextField: TextField can use object shorthand: TextField.

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

In `@examples/react/composition/src/AppForm/AppForm.tsx` around lines 16 - 21, The
export currently only exposes useAppForm from createFormHook; update the
destructuring returned by createFormHook to also export extendForm so downstream
modules can compose/extend the form (referencing createFormHook, useAppForm,
extendForm), and simplify the fieldComponents object by using shorthand for
TextField (replace TextField: TextField with TextField) while keeping
SubmitButton in formComponents.
🤖 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/react/guides/form-composition.md`:
- Around line 209-220: The example is incorrect: the package import casing was
changed and the example claims a name collision with CustomSubmit even though
ProfileForm defines SubmitButton; revert the import to the original casing
('weyland-yutan-corp/forms') and demonstrate a real collision by using the same
symbol name that ProfileForm actually exposes (e.g., use SubmitButton instead of
CustomSubmit) so TypeScript will error; update the export line that calls
ProfileForm.extendForm (reference: ProfileForm, useAppForm, CustomTextField,
CustomSubmit, SubmitButton) to import from the correctly-cased package and to
pass a formComponents object that actually collides with the parent
(SubmitButton) rather than CustomSubmit.

In `@examples/react/composition/src/AppForm/FieldComponents/TextField.tsx`:
- Around line 9-12: The TextField input is missing an onBlur handler so
field.state.meta.isTouched and onBlur validators won't update; update the input
rendered in the TextField component to add an onBlur that calls the form field's
blur handler (e.g., invoke field.handleBlur or the appropriate blur method on
the field object) so the field's touched state and onBlur validation run
correctly.

In `@examples/react/composition/src/index.tsx`:
- Around line 50-52: The firstName field in the form is using the wrong label;
update the AppField rendering for the firstName field (the instance that calls
form.AppField and renders {(f) => <f.TextField label="last name" />} ) to use
the correct label "first name" (i.e., change the label prop on f.TextField to
"first name" for the firstName AppField).

In `@packages/react-form/src/createFormHook.tsx`:
- Around line 599-617: extendForm currently only prevents extending keys that
exist in the parent maps but doesn't block names that collide with core runtime
APIs (e.g., AppForm, AppField, Field, Subscribe, handleChange) and thus can
silently override core behavior; modify extendForm to declare a reservedNames
set (include core exported API and runtime member names) and validate
extension.fieldComponents and extension.formComponents against that set,
rejecting/throwing with a clear error if any key from TNewField or TNewForm
appears in reservedNames; reference the extendForm function and the
fieldComponents/formComponents merge locations so the checks run before calling
createFormHook and before the cast to TComponents & TNewField / TFormComponents
& TNewForm.

---

Nitpick comments:
In `@examples/react/composition/index.html`:
- Line 9: Update the HTML <title> element to reflect this is the "Composition"
example rather than "Simple Example App": change the title text content inside
the <title> tag (currently "TanStack Form React Simple Example App") to
something like "TanStack Form React Composition Example" so it accurately
describes this example page.

In `@examples/react/composition/src/AppForm/AppForm.tsx`:
- Around line 16-21: The export currently only exposes useAppForm from
createFormHook; update the destructuring returned by createFormHook to also
export extendForm so downstream modules can compose/extend the form (referencing
createFormHook, useAppForm, extendForm), and simplify the fieldComponents object
by using shorthand for TextField (replace TextField: TextField with TextField)
while keeping SubmitButton in formComponents.

In `@examples/react/composition/src/index.tsx`:
- Around line 43-48: The async validator onChangeAsync currently returns the
string error when value.includes('error') is true but returns false when valid
due to the && expression; update the onChangeAsync implementation (the async
validator function) to explicitly return undefined for valid input instead of
false—e.g., replace the short-circuit expression with a conditional (ternary or
if) that returns 'No "error" allowed in first name' when value.includes('error')
is true and undefined otherwise.
- Around line 54-56: The lastName field's visible label is not
distinct/capitalized; update the form.AppField for name="lastName" to use a
proper, distinct label (e.g., change the f.TextField label prop to "Last Name")
and verify the other field (form.AppField name="firstName") uses "First Name" so
both fields are correctly labeled and consistently capitalized; look for usages
of form.AppField and the f.TextField label prop to make this change.

In `@packages/react-form/tests/createFormHook.test-d.tsx`:
- Around line 993-1021: The test never asserts that ThirdField survived the
second extendForm call; update the test around
useDoublyExtended/withExtendedForm to assert ThirdField is present — add
expectTypeOf(field.ThirdField).toBeFunction() inside the render callback
(alongside the existing Test and ExtendedField checks) and also assert the
doublyExtendedForm exposes the extended field (e.g., an assertion that the
useDoublyExtended result exposes ThirdField on AppField or the equivalent
exported shape) so the chaining regression would fail if the second extension
drops the key.
🪄 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: 89488856-d987-469f-8a56-da5c672e2719

📥 Commits

Reviewing files that changed from the base of the PR and between 4276176 and 23d9e03.

⛔ Files ignored due to path filters (2)
  • examples/react/composition/public/emblem-light.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • docs/framework/react/guides/form-composition.md
  • examples/react/composition/.eslintrc.cjs
  • examples/react/composition/.gitignore
  • examples/react/composition/README.md
  • examples/react/composition/index.html
  • examples/react/composition/package.json
  • examples/react/composition/src/AppForm/AppForm.tsx
  • examples/react/composition/src/AppForm/FieldComponents/TextField.tsx
  • examples/react/composition/src/AppForm/FormComponents/SubmitButton.tsx
  • examples/react/composition/src/index.tsx
  • examples/react/composition/tsconfig.json
  • packages/react-form/src/createFormHook.tsx
  • packages/react-form/tests/createFormHook.test-d.tsx
  • packages/react-form/tests/createFormHook.test.tsx

Copy link
Copy Markdown
Contributor

@LeCarbonator LeCarbonator left a comment

Choose a reason for hiding this comment

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

Essentially done! Once the threads are resolved / answered, this'll be ready to merge.

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.

♻️ Duplicate comments (1)
packages/react-form/src/createFormHook.tsx (1)

599-617: ⚠️ Potential issue | 🟠 Major

Prevent extendForm from shadowing built-in form members.

extendForm currently blocks only parent-map key collisions, but Line 614–617 can still inject names like AppField / AppForm that overwrite core members when merged at Line 388–392 (...formComponents is applied last). This can silently change runtime behavior.

Suggested fix
+ type ReservedFieldComponentNames = keyof AnyFieldApi
+ type ReservedFormComponentNames = keyof AnyFormApi | 'AppField' | 'AppForm'
+
   function extendForm<
     const TNewField extends Record<string, ComponentType<any>> & {
-      [K in keyof TComponents]?: 'Error: field component names must be unique — this key already exists in the base form'
+      [K in keyof TComponents | ReservedFieldComponentNames]?: 'Error: field component names must be unique and must not shadow field API members'
     },
     const TNewForm extends Record<string, ComponentType<any>> & {
-      [K in keyof TFormComponents]?: 'Error: form component names must be unique — this key already exists in the base form'
+      [K in keyof TFormComponents | ReservedFormComponentNames]?: 'Error: form component names must be unique and must not shadow form API members'
     },
   >(extension: { fieldComponents?: TNewField; formComponents?: TNewForm }) {
+    // Runtime guard for JS/any-casts
+    const reservedFormNames = new Set(['AppField', 'AppForm'])
+    for (const key of Object.keys(extension.formComponents ?? {})) {
+      if (reservedFormNames.has(key)) {
+        throw new Error(`extendForm: "${key}" is a reserved form component name`)
+      }
+    }
+
     return createFormHook({
       fieldContext,
       formContext,
#!/bin/bash
set -euo pipefail

file="$(fd -a createFormHook.tsx | head -n1)"

echo "== Merge order on extended form =="
nl -ba "$file" | sed -n '387,393p'

echo
echo "== extendForm generic constraints =="
nl -ba "$file" | sed -n '599,617p'

Expected verification result:

  • ...formComponents appears after AppField/AppForm.
  • extendForm constraints only reference base component maps and do not reserve core names.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-form/src/createFormHook.tsx` around lines 599 - 617,
extendForm currently allows extensions to define keys that collide with core
built-in members (e.g., AppField/AppForm) and thus can shadow them when merged
into formComponents/fieldComponents; update the extendForm generic constraints
(TNewField and TNewForm) to explicitly exclude the core built-in names (e.g.,
AppField, AppForm) so extension.fieldComponents/extension.formComponents cannot
declare those keys, and keep the createFormHook call using the same
fieldComponents/formComponents identifiers; reference extendForm, TNewField,
TNewForm, fieldComponents, formComponents, AppField, AppForm, and createFormHook
when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/react-form/src/createFormHook.tsx`:
- Around line 599-617: extendForm currently allows extensions to define keys
that collide with core built-in members (e.g., AppField/AppForm) and thus can
shadow them when merged into formComponents/fieldComponents; update the
extendForm generic constraints (TNewField and TNewForm) to explicitly exclude
the core built-in names (e.g., AppField, AppForm) so
extension.fieldComponents/extension.formComponents cannot declare those keys,
and keep the createFormHook call using the same fieldComponents/formComponents
identifiers; reference extendForm, TNewField, TNewForm, fieldComponents,
formComponents, AppField, AppForm, and createFormHook when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ec3e59b-2e28-48f5-8ac4-6a737eeb78a0

📥 Commits

Reviewing files that changed from the base of the PR and between 44898c5 and 3bc5c2d.

📒 Files selected for processing (4)
  • docs/framework/react/guides/form-composition.md
  • examples/react/composition/src/AppForm/FieldComponents/TextField.tsx
  • examples/react/composition/src/index.tsx
  • packages/react-form/src/createFormHook.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/react/composition/src/AppForm/FieldComponents/TextField.tsx
  • docs/framework/react/guides/form-composition.md

@harry-whorlow harry-whorlow merged commit d6ab662 into main Apr 10, 2026
9 checks passed
@harry-whorlow harry-whorlow deleted the extend-appform branch April 10, 2026 11:39
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.

2 participants