Skip to content

Commit 2ebad6a

Browse files
authored
[v2] Feat: Add Default options for React App Forms (#2336)
* feat: add default options to app form * docs: add JSDoc to react form composition * chore: generate docs and fix coderabbit * fix: remove nonsense type prop pick * chore: apply suggestions from coderabbit * chore: add istanbul coverage for adapters
1 parent 4341660 commit 2ebad6a

29 files changed

Lines changed: 1852 additions & 45 deletions

.changeset/gentle-forms-default.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/react-form': minor
3+
---
4+
5+
Add default form, field, and form group options to `createFormHook`.

.coderabbit.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ reviews:
33
base_branches:
44
- alpha
55
- main
6+
path_filters:
7+
- '!docs/reference/**'
8+
- '!docs/framework/*/reference/**'

docs/config.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,59 @@
357357
}
358358
]
359359
},
360+
{
361+
"label": "Form Composition API Reference",
362+
"collapsible": true,
363+
"defaultCollapsed": true,
364+
"children": [],
365+
"frameworks": [
366+
{
367+
"label": "react",
368+
"children": [
369+
{
370+
"label": "createFormHook()",
371+
"to": "framework/react/reference/functions/createFormHook"
372+
},
373+
{
374+
"label": "CreateFormHookOptions",
375+
"to": "framework/react/reference/interfaces/CreateFormHookOptions"
376+
},
377+
{
378+
"label": "AppFormHookResult",
379+
"to": "framework/react/reference/interfaces/AppFormHookResult"
380+
},
381+
{
382+
"label": "FormHookHelpers",
383+
"to": "framework/react/reference/interfaces/FormHookHelpers"
384+
},
385+
{
386+
"label": "FieldBrandHelper",
387+
"to": "framework/react/reference/interfaces/FieldBrandHelper"
388+
},
389+
{
390+
"label": "FieldComponentHelper",
391+
"to": "framework/react/reference/interfaces/FieldComponentHelper"
392+
},
393+
{
394+
"label": "defineFieldGroup()",
395+
"to": "framework/react/reference/variables/defineFieldGroup"
396+
},
397+
{
398+
"label": "FieldGroupApi",
399+
"to": "framework/react/reference/interfaces/FieldGroupApi"
400+
},
401+
{
402+
"label": "FieldGroupDefinition",
403+
"to": "framework/react/reference/interfaces/FieldGroupDefinition"
404+
},
405+
{
406+
"label": "FieldGroupHelper",
407+
"to": "framework/react/reference/interfaces/FieldGroupHelper"
408+
}
409+
]
410+
}
411+
]
412+
},
360413
{
361414
"label": "FormApi Reference",
362415
"collapsible": true,

docs/framework/preact/reference/interfaces/AppFormHookResult.md

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ title: AppFormHookResult
55

66
# Interface: AppFormHookResult\<TComponents\>
77

8-
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:25](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L25)
8+
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:31](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L31)
9+
10+
App Form hooks and helpers bound to the components registered with
11+
`createFormHook`.
912

1013
## Type Parameters
1114

1215
### TComponents
1316

1417
`TComponents` *extends* [`AnyPreactFormComponentMap`](../type-aliases/AnyPreactFormComponentMap.md)
1518

19+
Library-managed. Do not specify explicitly.
20+
1621
## Properties
1722

1823
### appFormOptions
@@ -21,7 +26,31 @@ Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:25](
2126
appFormOptions: AppFormOptionsApi<TComponents>;
2227
```
2328

24-
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:28](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L28)
29+
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:58](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L58)
30+
31+
Defines reusable form options that retain the components registered with
32+
`createFormHook`.
33+
34+
Use the result with `PreactFormType` when a child component needs the type
35+
of one known App Form, including its registered field and form components.
36+
37+
#### Example
38+
39+
```tsx
40+
const profileOptions = appFormOptions({
41+
defaultValues: { name: '' },
42+
})
43+
44+
type ProfileForm = PreactFormType<typeof profileOptions>
45+
46+
function NameField({ form }: { form: ProfileForm }) {
47+
return (
48+
<form.Field name="name">
49+
{(field) => <field.TextField label="Name" />}
50+
</form.Field>
51+
)
52+
}
53+
```
2554

2655
***
2756

@@ -31,7 +60,31 @@ Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:28](
3160
defineAppFieldGroup: DefineFieldGroupFn<TComponents["fieldComponents"]>;
3261
```
3362

34-
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:29](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L29)
63+
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:83](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L83)
64+
65+
Defines a reusable field group whose fields expose the field components
66+
registered with `createFormHook`.
67+
68+
#### Example
69+
70+
```tsx
71+
const contactFields = defineAppFieldGroup(({ strict }) => ({
72+
name: strict<string>(),
73+
email: strict<string>(),
74+
}))
75+
76+
function ContactFields({
77+
fields,
78+
}: {
79+
fields: typeof contactFields.fields
80+
}) {
81+
return (
82+
<fields.Field name="name">
83+
{(field) => <field.TextField label="Name" />}
84+
</fields.Field>
85+
)
86+
}
87+
```
3588

3689
***
3790

@@ -41,7 +94,31 @@ Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:29](
4194
useAppForm: UseAppFormHook<TComponents>;
4295
```
4396

44-
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:30](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L30)
97+
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:108](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L108)
98+
99+
Creates a Preact form API extended with the field and form components
100+
registered with `createFormHook`.
101+
102+
Form data, validators, and submission results are inferred from the passed
103+
options.
104+
105+
#### Example
106+
107+
```tsx
108+
function ProfileForm() {
109+
const form = useAppForm({
110+
defaultValues: { name: '' },
111+
})
112+
113+
return (
114+
<form.AppForm>
115+
<form.Field name="name">
116+
{(field) => <field.TextField label="Name" />}
117+
</form.Field>
118+
</form.AppForm>
119+
)
120+
}
121+
```
45122

46123
***
47124

@@ -51,8 +128,31 @@ Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:30](
51128
useFormContext: () => PreactAppFormApi<any, any, TComponents>;
52129
```
53130

54-
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:31](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L31)
131+
Defined in: [packages/preact-form/src/AppForm/createFormHookTypes.public.ts:132](https://github.com/TanStack/form/blob/main/packages/preact-form/src/AppForm/createFormHookTypes.public.ts#L132)
132+
133+
Reads the current App Form API from the nearest `form.AppForm` provider.
134+
135+
Use this hook inside form components registered with `createFormHook`. It
136+
throws when called outside a `form.AppForm` subtree.
55137

56138
#### Returns
57139

58140
[`PreactAppFormApi`](../type-aliases/PreactAppFormApi.md)\<`any`, `any`, `TComponents`\>
141+
142+
#### Example
143+
144+
```tsx
145+
function SubmitButton({ label }: { label: string }) {
146+
const form = useFormContext()
147+
148+
return (
149+
<form.Subscribe selector={(state) => state.isSubmitting}>
150+
{(isSubmitting) => (
151+
<button type="submit" disabled={isSubmitting}>
152+
{label}
153+
</button>
154+
)}
155+
</form.Subscribe>
156+
)
157+
}
158+
```

docs/framework/react/reference/functions/createFormHook.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,33 @@ title: createFormHook
66
# Function: createFormHook()
77

88
```ts
9-
function createFormHook<TComponents>(createOptions): AppFormHookResult<TComponents>;
9+
function createFormHook<TFormComponents, TFieldComponents>(createOptions): AppFormHookResult<{
10+
fieldComponents: TFieldComponents;
11+
formComponents: TFormComponents;
12+
}>;
1013
```
1114

12-
Defined in: [packages/react-form/src/AppForm/createFormHook.public.ts:20](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHook.public.ts#L20)
15+
Defined in: [packages/react-form/src/AppForm/createFormHook.public.ts:21](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/createFormHook.public.ts#L21)
1316

1417
## Type Parameters
1518

16-
### TComponents
19+
### TFormComponents
1720

18-
`TComponents` *extends* [`AnyReactFormComponentMap`](../type-aliases/AnyReactFormComponentMap.md)
21+
`TFormComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\>
22+
23+
### TFieldComponents
24+
25+
`TFieldComponents` *extends* `Record`\<`string`, `FunctionComponent`\<`any`\>\>
1926

2027
## Parameters
2128

2229
### createOptions
2330

24-
`TComponents`
31+
[`CreateFormHookOptions`](../interfaces/CreateFormHookOptions.md)\<`TFormComponents`, `TFieldComponents`\>
2532

2633
## Returns
2734

28-
[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<`TComponents`\>
35+
[`AppFormHookResult`](../interfaces/AppFormHookResult.md)\<\{
36+
`fieldComponents`: `TFieldComponents`;
37+
`formComponents`: `TFormComponents`;
38+
\}\>

docs/framework/react/reference/functions/getFormHookHelpers.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,39 @@ title: getFormHookHelpers
99
function getFormHookHelpers(): FormHookHelpers;
1010
```
1111

12-
Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:101](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L101)
12+
Defined in: [packages/react-form/src/AppForm/getFormHookHelpers.public.ts:268](https://github.com/TanStack/form/blob/main/packages/react-form/src/AppForm/getFormHookHelpers.public.ts#L268)
13+
14+
Creates helpers that make React field components value-aware for
15+
`createFormHook`.
16+
17+
`fieldComponent` injects the current App Form field API into a selected prop.
18+
`fieldBrand` only adds compile-time field-value compatibility and returns the
19+
original component at runtime.
1320

1421
## Returns
1522

1623
[`FormHookHelpers`](../interfaces/FormHookHelpers.md)
24+
25+
## Example
26+
27+
```tsx
28+
import { createFormHook, getFormHookHelpers } from '@tanstack/react-form'
29+
import type { FieldWithValue } from '@tanstack/react-form'
30+
31+
function TextInput({ field }: { field: FieldWithValue<string> }) {
32+
return (
33+
<input
34+
value={field.value}
35+
onChange={(event) => field.handleChange(event.target.value)}
36+
/>
37+
)
38+
}
39+
40+
const { fieldComponent } = getFormHookHelpers()
41+
const TextField = fieldComponent.strict(TextInput, 'field')
42+
43+
export const { useAppForm } = createFormHook({
44+
fieldComponents: { TextField },
45+
formComponents: {},
46+
})
47+
```

docs/framework/react/reference/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ title: "@tanstack/react-form"
1818
- [Atom](interfaces/Atom.md)
1919
- [AtomOptions](interfaces/AtomOptions.md)
2020
- [BaseAtom](interfaces/BaseAtom.md)
21+
- [CreateFormHookOptions](interfaces/CreateFormHookOptions.md)
22+
- [FieldBrandHelper](interfaces/FieldBrandHelper.md)
23+
- [FieldComponentHelper](interfaces/FieldComponentHelper.md)
2124
- [FieldGroupApi](interfaces/FieldGroupApi.md)
2225
- [FieldGroupArrayFieldComponent](interfaces/FieldGroupArrayFieldComponent.md)
2326
- [FieldGroupDefinition](interfaces/FieldGroupDefinition.md)
@@ -50,6 +53,9 @@ title: "@tanstack/react-form"
5053
- [AnyReactFormApi](type-aliases/AnyReactFormApi.md)
5154
- [AnyReactFormComponentMap](type-aliases/AnyReactFormComponentMap.md)
5255
- [AppFormComponent](type-aliases/AppFormComponent.md)
56+
- [CreateFormHookDefaultFieldOptions](type-aliases/CreateFormHookDefaultFieldOptions.md)
57+
- [CreateFormHookDefaultFormGroupOptions](type-aliases/CreateFormHookDefaultFormGroupOptions.md)
58+
- [CreateFormHookDefaultFormOptions](type-aliases/CreateFormHookDefaultFormOptions.md)
5359
- [DefaultReactFormComponentMap](type-aliases/DefaultReactFormComponentMap.md)
5460
- [DefineFieldGroupFn](type-aliases/DefineFieldGroupFn.md)
5561
- [FieldGroupFieldBindingForSlot](type-aliases/FieldGroupFieldBindingForSlot.md)

0 commit comments

Comments
 (0)