@primereact/mcp 11.0.0 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/data/llms/headless/components/accordion/api.json +9 -9
  2. package/data/llms/headless/components/animateonscroll/api.json +2 -2
  3. package/data/llms/headless/components/autocomplete/api.json +33 -33
  4. package/data/llms/headless/components/avatar/api.json +1 -1
  5. package/data/llms/headless/components/carousel/api.json +15 -15
  6. package/data/llms/headless/components/checkbox/api.json +18 -18
  7. package/data/llms/headless/components/collapsible/api.json +14 -14
  8. package/data/llms/headless/components/compare/api.json +3 -3
  9. package/data/llms/headless/components/contextmenu/api.json +2 -2
  10. package/data/llms/headless/components/datatable/api.json +19 -19
  11. package/data/llms/headless/components/dataview/api.json +3 -3
  12. package/data/llms/headless/components/datepicker/api.json +43 -43
  13. package/data/llms/headless/components/dialog/api.json +19 -19
  14. package/data/llms/headless/components/divider/api.json +3 -3
  15. package/data/llms/headless/components/drawer/api.json +13 -13
  16. package/data/llms/headless/components/fieldset/api.json +9 -9
  17. package/data/llms/headless/components/fileupload/api.json +5 -5
  18. package/data/llms/headless/components/focustrap/api.json +4 -4
  19. package/data/llms/headless/components/gallery/api.json +23 -23
  20. package/data/llms/headless/components/inplace/api.json +3 -3
  21. package/data/llms/headless/components/inputcolor/api.json +6 -6
  22. package/data/llms/headless/components/inputcolor.md +0 -1
  23. package/data/llms/headless/components/inputnumber/api.json +8 -8
  24. package/data/llms/headless/components/inputotp/api.json +7 -7
  25. package/data/llms/headless/components/inputpassword/api.json +4 -4
  26. package/data/llms/headless/components/inputpassword.md +3 -3
  27. package/data/llms/headless/components/inputtags/api.json +8 -8
  28. package/data/llms/headless/components/inputtext/api.json +1 -1
  29. package/data/llms/headless/components/knob/api.json +18 -18
  30. package/data/llms/headless/components/listbox/api.json +27 -27
  31. package/data/llms/headless/components/menu/api.json +10 -10
  32. package/data/llms/headless/components/message/api.json +1 -1
  33. package/data/llms/headless/components/metergroup/api.json +3 -3
  34. package/data/llms/headless/components/motion/api.json +1 -1
  35. package/data/llms/headless/components/navigationmenu/api.json +5 -5
  36. package/data/llms/headless/components/orderlist/api.json +5 -5
  37. package/data/llms/headless/components/organizationchart/api.json +6 -6
  38. package/data/llms/headless/components/paginator/api.json +5 -5
  39. package/data/llms/headless/components/panel/api.json +9 -9
  40. package/data/llms/headless/components/picklist/api.json +5 -5
  41. package/data/llms/headless/components/popover/api.json +16 -16
  42. package/data/llms/headless/components/positioner/api.json +7 -7
  43. package/data/llms/headless/components/progressbar/api.json +3 -3
  44. package/data/llms/headless/components/progressspinner/api.json +3 -3
  45. package/data/llms/headless/components/radiobutton/api.json +16 -16
  46. package/data/llms/headless/components/rating/api.json +5 -5
  47. package/data/llms/headless/components/scrollarea/api.json +6 -6
  48. package/data/llms/headless/components/select/api.json +34 -34
  49. package/data/llms/headless/components/sidebar/api.json +1116 -141
  50. package/data/llms/headless/components/sidebar.md +4 -2
  51. package/data/llms/headless/components/slider/api.json +3 -3
  52. package/data/llms/headless/components/speeddial/api.json +4 -4
  53. package/data/llms/headless/components/splitter/api.json +5 -5
  54. package/data/llms/headless/components/stepper/api.json +13 -13
  55. package/data/llms/headless/components/styleclass/api.json +1 -1
  56. package/data/llms/headless/components/tabs/api.json +17 -17
  57. package/data/llms/headless/components/terminal/api.json +1 -1
  58. package/data/llms/headless/components/toast/api.json +4 -4
  59. package/data/llms/headless/components/togglebutton/api.json +27 -3
  60. package/data/llms/headless/components/toggleswitch/api.json +3 -3
  61. package/data/llms/headless/components/tooltip/api.json +17 -17
  62. package/data/llms/headless/components/tree/api.json +20 -20
  63. package/data/llms/headless/components/tree.md +1 -0
  64. package/data/llms/headless/components/treetable/api.json +19 -19
  65. package/data/llms/headless/guides/misc/internationalization.md +282 -0
  66. package/data/llms/hooks/use-filter.md +2 -2
  67. package/data/llms/hooks/use-tree-filter.md +3 -1
  68. package/data/llms/llms-full.txt +10444 -1743
  69. package/data/llms/llms.txt +15 -0
  70. package/data/llms/primitive/components/accordion/api.json +39 -39
  71. package/data/llms/primitive/components/animateonscroll/api.json +5 -5
  72. package/data/llms/primitive/components/autocomplete/api.json +105 -105
  73. package/data/llms/primitive/components/avatar/api.json +14 -14
  74. package/data/llms/primitive/components/badge/api.json +6 -6
  75. package/data/llms/primitive/components/breadcrumb/api.json +27 -27
  76. package/data/llms/primitive/components/button/api.json +8 -8
  77. package/data/llms/primitive/components/buttongroup/api.json +3 -3
  78. package/data/llms/primitive/components/card/api.json +24 -24
  79. package/data/llms/primitive/components/carousel/api.json +28 -28
  80. package/data/llms/primitive/components/checkbox/api.json +14 -14
  81. package/data/llms/primitive/components/checkboxgroup/api.json +5 -5
  82. package/data/llms/primitive/components/chip/api.json +19 -19
  83. package/data/llms/primitive/components/collapsible/api.json +18 -18
  84. package/data/llms/primitive/components/compare/api.json +18 -18
  85. package/data/llms/primitive/components/contextmenu/api.json +150 -1141
  86. package/data/llms/primitive/components/datatable/api.json +215 -164
  87. package/data/llms/primitive/components/dataview/api.json +17 -17
  88. package/data/llms/primitive/components/datepicker/api.json +230 -230
  89. package/data/llms/primitive/components/dialog/api.json +63 -63
  90. package/data/llms/primitive/components/divider/api.json +3 -3
  91. package/data/llms/primitive/components/drawer/api.json +47 -47
  92. package/data/llms/primitive/components/fieldset/api.json +31 -31
  93. package/data/llms/primitive/components/fileupload/api.json +53 -53
  94. package/data/llms/primitive/components/floatlabel/api.json +3 -3
  95. package/data/llms/primitive/components/focustrap/api.json +7 -7
  96. package/data/llms/primitive/components/gallery/api.json +91 -91
  97. package/data/llms/primitive/components/iconfield/api.json +7 -7
  98. package/data/llms/primitive/components/iftalabel/api.json +3 -3
  99. package/data/llms/primitive/components/inplace/api.json +18 -18
  100. package/data/llms/primitive/components/inputcolor/api.json +51 -51
  101. package/data/llms/primitive/components/inputnumber/api.json +10 -10
  102. package/data/llms/primitive/components/inputotp/api.json +12 -12
  103. package/data/llms/primitive/components/inputpassword/api.json +7 -7
  104. package/data/llms/primitive/components/inputtags/api.json +6 -6
  105. package/data/llms/primitive/components/inputtext/api.json +4 -4
  106. package/data/llms/primitive/components/knob/api.json +19 -19
  107. package/data/llms/primitive/components/label/api.json +3 -3
  108. package/data/llms/primitive/components/listbox/api.json +57 -57
  109. package/data/llms/primitive/components/menu/api.json +87 -279
  110. package/data/llms/primitive/components/message/api.json +22 -22
  111. package/data/llms/primitive/components/metergroup/api.json +27 -27
  112. package/data/llms/primitive/components/navigationmenu/api.json +8 -8
  113. package/data/llms/primitive/components/paginator/api.json +43 -43
  114. package/data/llms/primitive/components/panel/api.json +34 -34
  115. package/data/llms/primitive/components/popover/api.json +67 -67
  116. package/data/llms/primitive/components/portal/api.json +4 -4
  117. package/data/llms/primitive/components/progressbar/api.json +22 -22
  118. package/data/llms/primitive/components/progressspinner/api.json +18 -18
  119. package/data/llms/primitive/components/radiobutton/api.json +16 -16
  120. package/data/llms/primitive/components/rating/api.json +20 -20
  121. package/data/llms/primitive/components/scrollarea/api.json +23 -23
  122. package/data/llms/primitive/components/select/api.json +95 -95
  123. package/data/llms/primitive/components/sidebar/api.json +215 -121
  124. package/data/llms/primitive/components/sidebar.md +2 -1
  125. package/data/llms/primitive/components/skeleton/api.json +3 -3
  126. package/data/llms/primitive/components/slider/api.json +22 -22
  127. package/data/llms/primitive/components/speeddial/api.json +22 -22
  128. package/data/llms/primitive/components/splitter/api.json +18 -18
  129. package/data/llms/primitive/components/stepper/api.json +64 -64
  130. package/data/llms/primitive/components/tabs/api.json +51 -51
  131. package/data/llms/primitive/components/tag/api.json +3 -3
  132. package/data/llms/primitive/components/terminal/api.json +44 -44
  133. package/data/llms/primitive/components/textarea/api.json +4 -4
  134. package/data/llms/primitive/components/timeline/api.json +27 -27
  135. package/data/llms/primitive/components/toast/api.json +48 -48
  136. package/data/llms/primitive/components/togglebutton/api.json +10 -10
  137. package/data/llms/primitive/components/togglebuttongroup/api.json +5 -5
  138. package/data/llms/primitive/components/toggleswitch/api.json +12 -12
  139. package/data/llms/primitive/components/toolbar/api.json +15 -15
  140. package/data/llms/primitive/components/tooltip/api.json +52 -52
  141. package/data/llms/primitive/components/tree/api.json +73 -73
  142. package/data/llms/primitive/components/visuallyhidden/api.json +3 -3
  143. package/data/llms/primitive/guides/migration/updating-to-v11.md +2219 -0
  144. package/data/llms/primitive/guides/misc/internationalization.md +287 -0
  145. package/data/llms/styled/add-ons/designer/ci.md +273 -0
  146. package/data/llms/styled/add-ons/designer/guide.md +99 -0
  147. package/data/llms/styled/add-ons/designer/overview.md +194 -0
  148. package/data/llms/styled/add-ons/uikit/guide/v3.md +182 -0
  149. package/data/llms/styled/add-ons/uikit/guide/v4.md +163 -0
  150. package/data/llms/styled/add-ons/uikit/overview.md +204 -0
  151. package/data/llms/styled/components/button/api.json +8 -8
  152. package/data/llms/styled/components/carousel.md +65 -0
  153. package/data/llms/styled/components/datatable.md +101 -88
  154. package/data/llms/styled/components/floatlabel/api.json +3 -3
  155. package/data/llms/styled/components/fluid/api.json +3 -3
  156. package/data/llms/styled/components/iconfield/api.json +7 -7
  157. package/data/llms/styled/components/iftalabel/api.json +3 -3
  158. package/data/llms/styled/components/inputcolor.md +3 -0
  159. package/data/llms/styled/components/inputgroup/api.json +7 -7
  160. package/data/llms/styled/components/label/api.json +3 -3
  161. package/data/llms/styled/components/menu.md +39 -41
  162. package/data/llms/styled/components/organizationchart/api.json +33 -33
  163. package/data/llms/styled/components/rating/api.json +11 -11
  164. package/data/llms/styled/components/select.md +6 -0
  165. package/data/llms/styled/components/sidebar.md +12 -8
  166. package/data/llms/styled/components/tree.md +5 -0
  167. package/data/llms/styled/components/treetable.md +171 -62
  168. package/data/llms/styled/guides/configuration.md +223 -0
  169. package/data/llms/styled/guides/form/formik.md +448 -0
  170. package/data/llms/styled/guides/form/react-hook-form.md +503 -0
  171. package/data/llms/styled/guides/form/tanstack.md +502 -0
  172. package/data/llms/styled/guides/migration/updating-to-v11.md +2219 -0
  173. package/data/llms/styled/guides/misc/internationalization.md +379 -0
  174. package/data/llms/styled/guides/theming/tailwind.md +25 -0
  175. package/data/llms/tailwind/components/button/api.json +8 -8
  176. package/data/llms/tailwind/components/datatable.md +33 -42
  177. package/data/llms/tailwind/components/inputgroup.md +0 -1
  178. package/data/llms/tailwind/components/menu.md +5 -5
  179. package/data/llms/tailwind/components/select.md +3 -0
  180. package/data/llms/tailwind/components/sidebar.md +16 -11
  181. package/data/llms/tailwind/components/tooltip.md +4 -13
  182. package/data/llms/tailwind/guides/misc/internationalization.md +287 -0
  183. package/data/manifest.json +1089 -779
  184. package/data/mcp-data.json +263 -32
  185. package/dist/index.d.ts +7 -2
  186. package/dist/index.js +1 -1
  187. package/package.json +9 -8
  188. package/data/llms/styled/guides/installation/configuration.md +0 -135
  189. package/data/llms/tailwind/guides/theming/guide.md +0 -179
@@ -0,0 +1,502 @@
1
+ # TanStack Form
2
+
3
+ Build validated forms with PrimeReact and TanStack Form.
4
+
5
+ <DocMessage>
6
+ Open the <a href="https://stackblitz.com/edit/vitejs-vite-bluiv8e7?file=src%2Fcomponents%2Ftanstack-form.tsx" target="_blank" rel="noopener noreferrer">complete example on StackBlitz</a> to run and edit the form built in this guide.
7
+ </DocMessage>
8
+
9
+ ## Introduction
10
+
11
+ [TanStack Form](https://tanstack.com/form) is a headless, fully type-safe form library. Fields are declared with the `form.Field` component, and each one owns its value and handlers. PrimeReact inputs are controlled, so they read from `field.state.value` and report through `field.handleChange`.
12
+
13
+ TanStack Form implements the [Standard Schema](https://github.com/standard-schema/standard-schema) spec, so a [Zod](https://zod.dev/) schema plugs straight into `validators` with no adapter.
14
+
15
+ ```bash
16
+ npm install @tanstack/react-form zod
17
+ ```
18
+
19
+ ## Anatomy
20
+
21
+ A field is a `form.Field` whose render callback receives a `field` object. Read the value from `field.state.value`, push changes with `field.handleChange`, and mark it visited with `field.handleBlur`:
22
+
23
+ ```tsx title="Anatomy" showLineNumbers
24
+ <form.Field name="projectName">
25
+ {(field) => (
26
+ <InputText
27
+ id={field.name}
28
+ value={field.state.value} // current value
29
+ onChange={(e) => field.handleChange(e.target.value)} // push the change
30
+ onBlur={field.handleBlur} // mark as touched
31
+ invalid={field.state.meta.errors.length > 0} // error styling
32
+ />
33
+ )}
34
+ </form.Field>
35
+ ```
36
+
37
+ - **`field.state.value`**: the current value of this field.
38
+ - **`field.handleChange` / `field.handleBlur`**: update the value and the touched state.
39
+ - **`field.state.meta`**: the field's status (`errors`, `isTouched`, `isDirty`, `isValidating`).
40
+
41
+ Native inputs report a DOM event, so pass `e.target.value`. Composite components report their own value, covered in [Fields](#fields).
42
+
43
+ ## Create the form
44
+
45
+ ### Schema
46
+
47
+ Describe the shape and rules of the form with Zod. The message passed to each rule is what surfaces as the field error:
48
+
49
+ ```tsx title="schema.ts" showLineNumbers
50
+ import { z } from 'zod';
51
+
52
+ export const schema = z.object({
53
+ projectName: z.string().min(1, 'Project name is required.'),
54
+ framework: z.string().min(1, 'Please select a framework.'),
55
+ rootDir: z.string().min(1, 'Root directory is required.'),
56
+ environments: z.array(z.string()).min(1, 'Select at least one environment.')
57
+ });
58
+
59
+ export type FormValues = z.infer<typeof schema>;
60
+ ```
61
+
62
+ ### Connect to TanStack Form
63
+
64
+ Create the form with `useForm`. Provide `defaultValues` for every field, pass the schema to `validators`, and handle the typed `value` in `onSubmit`:
65
+
66
+ ```tsx title="deploy-form.tsx" showLineNumbers {5,6}
67
+ import { useForm } from '@tanstack/react-form';
68
+ import { schema } from './schema';
69
+
70
+ const form = useForm({
71
+ defaultValues: { projectName: '', framework: '', rootDir: './', environments: [] as string[] },
72
+ validators: { onChange: schema },
73
+ onSubmit: ({ value }) => {
74
+ console.log(value);
75
+ }
76
+ });
77
+ ```
78
+
79
+ <DocMessage>
80
+ `validators` accepts any Standard Schema validator, so you can swap Zod for Valibot or ArkType without changing anything else. Attach `onBlur` or `onSubmit` validators instead of `onChange` to control timing.
81
+ </DocMessage>
82
+
83
+ ### Submit
84
+
85
+ TanStack Form does not hijack the native submit, so prevent the default and call `form.handleSubmit` yourself. It validates first and only runs your `onSubmit` when every field passes:
86
+
87
+ ```tsx title="Submit" showLineNumbers
88
+ return (
89
+ <form
90
+ onSubmit={(e) => {
91
+ e.preventDefault();
92
+ e.stopPropagation();
93
+ form.handleSubmit();
94
+ }}
95
+ className="flex flex-col gap-6"
96
+ >
97
+ {/* fields go here */}
98
+ <Button type="submit">Deploy</Button>
99
+ </form>
100
+ );
101
+ ```
102
+
103
+ ### Reset
104
+
105
+ Call `form.reset()` to clear every field back to `defaultValues`, or pass an object to seed the form with new values instead, for example after a successful submit:
106
+
107
+ ```tsx title="Reset"
108
+ // restore the defaults
109
+ <Button type="button" severity="secondary" variant="outlined" onClick={() => form.reset()}>
110
+ Reset
111
+ </Button>;
112
+
113
+ // or set new values
114
+ form.reset({ projectName: 'my-app', framework: 'nextjs', rootDir: './', environments: ['production'] });
115
+ ```
116
+
117
+ ### Result
118
+
119
+ Everything above comes together as the complete form. `form.Subscribe` reads the live form state so the submit button can disable itself while the form is invalid or submitting. Each field is broken down in [Fields](#fields):
120
+
121
+ <div className="[&_pre]:max-h-[32rem] [&_pre]:overflow-y-auto">
122
+
123
+ ```tsx title="deploy-form.tsx" showLineNumbers
124
+ 'use client';
125
+ import { useForm } from '@tanstack/react-form';
126
+ import { z } from 'zod';
127
+ import { ChevronDown, Check } from '@primeicons/react';
128
+ import { InputText } from '@primereact/ui/inputtext';
129
+ import { Select } from '@primereact/ui/select';
130
+ import { Checkbox } from '@primereact/ui/checkbox';
131
+ import { CheckboxGroup } from '@primereact/ui/checkboxgroup';
132
+ import { Label } from '@primereact/ui/label';
133
+ import { Button } from '@primereact/ui/button';
134
+ import { Message } from '@primereact/ui/message';
135
+
136
+ const FRAMEWORKS = [
137
+ { label: 'Next.js', value: 'nextjs' },
138
+ { label: 'Vite', value: 'vite' },
139
+ { label: 'Astro', value: 'astro' }
140
+ ];
141
+
142
+ const ENVIRONMENTS = [
143
+ { label: 'Production', value: 'production' },
144
+ { label: 'Preview', value: 'preview' },
145
+ { label: 'Development', value: 'development' }
146
+ ];
147
+
148
+ const schema = z.object({
149
+ projectName: z.string().min(1, 'Project name is required.'),
150
+ framework: z.string().min(1, 'Please select a framework.'),
151
+ rootDir: z.string().min(1, 'Root directory is required.'),
152
+ environments: z.array(z.string()).min(1, 'Select at least one environment.')
153
+ });
154
+
155
+ export default function DeployForm() {
156
+ const form = useForm({
157
+ defaultValues: { projectName: '', framework: '', rootDir: './', environments: [] as string[] },
158
+ validators: { onChange: schema },
159
+ onSubmit: ({ value }) => {
160
+ console.log(value);
161
+ }
162
+ });
163
+
164
+ return (
165
+ <form
166
+ onSubmit={(e) => {
167
+ e.preventDefault();
168
+ e.stopPropagation();
169
+ form.handleSubmit();
170
+ }}
171
+ className="flex flex-col gap-6"
172
+ >
173
+ <form.Field name="projectName">
174
+ {(field) => (
175
+ <div className="flex flex-col gap-2">
176
+ <Label htmlFor={field.name}>Project name</Label>
177
+ <InputText id={field.name} value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} onBlur={field.handleBlur} invalid={field.state.meta.errors.length > 0} fluid />
178
+ {field.state.meta.errors.length > 0 && (
179
+ <Message.Root severity="error" variant="simple" size="small">
180
+ <Message.Content>
181
+ <Message.Text>{field.state.meta.errors[0]?.message}</Message.Text>
182
+ </Message.Content>
183
+ </Message.Root>
184
+ )}
185
+ </div>
186
+ )}
187
+ </form.Field>
188
+
189
+ <form.Field name="framework">
190
+ {(field) => (
191
+ <div className="flex flex-col gap-2">
192
+ <Label htmlFor={field.name}>Framework preset</Label>
193
+ <Select.Root
194
+ value={field.state.value}
195
+ onValueChange={(e) => field.handleChange(e.value as string)}
196
+ onBlur={field.handleBlur}
197
+ options={FRAMEWORKS}
198
+ optionLabel="label"
199
+ optionValue="value"
200
+ invalid={field.state.meta.errors.length > 0}
201
+ >
202
+ <Select.Trigger type="button">
203
+ <Select.Value placeholder="Select a framework" />
204
+ <Select.Indicator>
205
+ <ChevronDown />
206
+ </Select.Indicator>
207
+ </Select.Trigger>
208
+ <Select.Portal>
209
+ <Select.Positioner>
210
+ <Select.Popup>
211
+ <Select.List />
212
+ </Select.Popup>
213
+ </Select.Positioner>
214
+ </Select.Portal>
215
+ </Select.Root>
216
+ {field.state.meta.errors.length > 0 && (
217
+ <Message.Root severity="error" variant="simple" size="small">
218
+ <Message.Content>
219
+ <Message.Text>{field.state.meta.errors[0]?.message}</Message.Text>
220
+ </Message.Content>
221
+ </Message.Root>
222
+ )}
223
+ </div>
224
+ )}
225
+ </form.Field>
226
+
227
+ <form.Field name="rootDir">
228
+ {(field) => (
229
+ <div className="flex flex-col gap-2">
230
+ <Label htmlFor={field.name}>Root directory</Label>
231
+ <InputText id={field.name} value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} onBlur={field.handleBlur} invalid={field.state.meta.errors.length > 0} fluid />
232
+ {field.state.meta.errors.length > 0 && (
233
+ <Message.Root severity="error" variant="simple" size="small">
234
+ <Message.Content>
235
+ <Message.Text>{field.state.meta.errors[0]?.message}</Message.Text>
236
+ </Message.Content>
237
+ </Message.Root>
238
+ )}
239
+ </div>
240
+ )}
241
+ </form.Field>
242
+
243
+ <form.Field name="environments">
244
+ {(field) => (
245
+ <div className="flex flex-col gap-2">
246
+ <Label>Environments</Label>
247
+ <CheckboxGroup value={field.state.value} onValueChange={(e) => field.handleChange(e.value as string[])}>
248
+ {ENVIRONMENTS.map((env) => (
249
+ <div key={env.value} className="flex items-center gap-2">
250
+ <Checkbox.Root inputId={env.value} value={env.value}>
251
+ <Checkbox.Box>
252
+ <Checkbox.Indicator match="checked">
253
+ <Check />
254
+ </Checkbox.Indicator>
255
+ </Checkbox.Box>
256
+ </Checkbox.Root>
257
+ <Label htmlFor={env.value}>{env.label}</Label>
258
+ </div>
259
+ ))}
260
+ </CheckboxGroup>
261
+ {field.state.meta.errors.length > 0 && (
262
+ <Message.Root severity="error" variant="simple" size="small">
263
+ <Message.Content>
264
+ <Message.Text>{field.state.meta.errors[0]?.message}</Message.Text>
265
+ </Message.Content>
266
+ </Message.Root>
267
+ )}
268
+ </div>
269
+ )}
270
+ </form.Field>
271
+
272
+ <div className="flex justify-end gap-3">
273
+ <Button type="button" severity="secondary" variant="outlined" onClick={() => form.reset()}>
274
+ Reset
275
+ </Button>
276
+ <form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]}>
277
+ {([canSubmit, isSubmitting]) => (
278
+ <Button type="submit" disabled={!canSubmit}>
279
+ {isSubmitting ? 'Deploying…' : 'Deploy'}
280
+ </Button>
281
+ )}
282
+ </form.Subscribe>
283
+ </div>
284
+ </form>
285
+ );
286
+ }
287
+ ```
288
+
289
+ </div>
290
+
291
+ ## Fields
292
+
293
+ Every field is a `form.Field`. How you forward the change depends on the component:
294
+
295
+ - **Native inputs**: `InputText` and `Textarea` render a real `<input>` / `<textarea>` and report a DOM event, so pass `e.target.value` to `field.handleChange`.
296
+ - **Composite inputs**: `Select`, `Checkbox`, `RadioButtonGroup` and `CheckboxGroup` report through `onValueChange` / `onCheckedChange` with an event object, so forward `event.value` / `event.checked`.
297
+
298
+ Bind `invalid={field.state.meta.errors.length > 0}` on any component to get error styling.
299
+
300
+ ### InputText
301
+
302
+ ```tsx title="InputText"
303
+ <form.Field name="projectName">
304
+ {(field) => (
305
+ <div className="flex flex-col gap-2">
306
+ <Label htmlFor={field.name}>Project name</Label>
307
+ <InputText id={field.name} value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} onBlur={field.handleBlur} invalid={field.state.meta.errors.length > 0} fluid />
308
+ </div>
309
+ )}
310
+ </form.Field>
311
+ ```
312
+
313
+ ### Select
314
+
315
+ ```tsx title="Select"
316
+ <form.Field name="framework">
317
+ {(field) => (
318
+ <Select.Root value={field.state.value} onValueChange={(e) => field.handleChange(e.value as string)} onBlur={field.handleBlur} options={FRAMEWORKS} optionLabel="label" optionValue="value" invalid={field.state.meta.errors.length > 0}>
319
+ <Select.Trigger type="button">
320
+ <Select.Value placeholder="Select a framework" />
321
+ <Select.Indicator>
322
+ <ChevronDown />
323
+ </Select.Indicator>
324
+ </Select.Trigger>
325
+ <Select.Portal>
326
+ <Select.Positioner>
327
+ <Select.Popup>
328
+ <Select.List />
329
+ </Select.Popup>
330
+ </Select.Positioner>
331
+ </Select.Portal>
332
+ </Select.Root>
333
+ )}
334
+ </form.Field>
335
+ ```
336
+
337
+ ### Checkbox
338
+
339
+ A single checkbox is a boolean, so bind `checked` and forward `event.checked`:
340
+
341
+ ```tsx title="Checkbox"
342
+ <form.Field name="agree">
343
+ {(field) => (
344
+ <Checkbox.Root checked={field.state.value} onCheckedChange={(e) => field.handleChange(e.checked)}>
345
+ <Checkbox.Box>
346
+ <Checkbox.Indicator match="checked">
347
+ <Check />
348
+ </Checkbox.Indicator>
349
+ </Checkbox.Box>
350
+ </Checkbox.Root>
351
+ )}
352
+ </form.Field>
353
+ ```
354
+
355
+ ### Groups
356
+
357
+ `RadioButtonGroup`, `CheckboxGroup` and `ToggleButtonGroup` own a single value for the whole group, so wrap the group (not each item) in one `form.Field`:
358
+
359
+ ```tsx title="CheckboxGroup"
360
+ <form.Field name="environments">
361
+ {(field) => (
362
+ <CheckboxGroup value={field.state.value} onValueChange={(e) => field.handleChange(e.value as string[])}>
363
+ {ENVIRONMENTS.map((env) => (
364
+ <div key={env.value} className="flex items-center gap-2">
365
+ <Checkbox.Root inputId={env.value} value={env.value}>
366
+ <Checkbox.Box>
367
+ <Checkbox.Indicator match="checked">
368
+ <Check />
369
+ </Checkbox.Indicator>
370
+ </Checkbox.Box>
371
+ </Checkbox.Root>
372
+ <Label htmlFor={env.value}>{env.label}</Label>
373
+ </div>
374
+ ))}
375
+ </CheckboxGroup>
376
+ )}
377
+ </form.Field>
378
+ ```
379
+
380
+ ### Value types
381
+
382
+ Most inputs hold a string, but some do not. Match the schema and the `defaultValues` to the value type:
383
+
384
+ - `InputNumber`, `Slider`, `Rating` → `number` (`z.number()`)
385
+ - `DatePicker` → `Date` (`z.date()`)
386
+ - `Checkbox`, `ToggleSwitch`, `ToggleButton` → `boolean` (`z.boolean()`)
387
+ - `CheckboxGroup`, multiple `Select`, `InputTags` → `array` (`z.array(...)`)
388
+
389
+ <DocMessage>
390
+ Number and date fields start as `null`, not `''`. An empty string breaks their value type.
391
+ </DocMessage>
392
+
393
+ ## Validation
394
+
395
+ ### When it runs
396
+
397
+ Attach the schema to the timing you want under `validators`. You can set them on the whole form or on an individual `form.Field`:
398
+
399
+ ```tsx
400
+ // whole form
401
+ useForm({ validators: { onChange: schema } });
402
+
403
+ // single field
404
+ <form.Field name="projectName" validators={{ onBlur: z.string().min(1, 'Required.') }}>
405
+ ```
406
+
407
+ | Validator | Runs |
408
+ | --------------- | -------------------------------- |
409
+ | `onChange` | on every keystroke / change |
410
+ | `onBlur` | when a field loses focus |
411
+ | `onSubmit` | on submit only |
412
+ | `onChangeAsync` | debounced async check (e.g. API) |
413
+
414
+ Field-level validators run alongside the form-level ones, so you can layer a cheap sync rule with an async uniqueness check.
415
+
416
+ ### Showing errors
417
+
418
+ `field.state.meta.errors` is an array of the schema issues for that field. Render the first message with the `Message` component in the `simple` variant so it sits inline under the field:
419
+
420
+ ```tsx title="Error message"
421
+ <form.Field name="projectName">
422
+ {(field) => (
423
+ <div className="flex flex-col gap-2">
424
+ <Label htmlFor={field.name}>Project name</Label>
425
+ <InputText id={field.name} value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} onBlur={field.handleBlur} invalid={field.state.meta.errors.length > 0} fluid />
426
+ {field.state.meta.errors.length > 0 && (
427
+ <Message.Root severity="error" variant="simple" size="small">
428
+ <Message.Content>
429
+ <Message.Text>{field.state.meta.errors[0]?.message}</Message.Text>
430
+ </Message.Content>
431
+ </Message.Root>
432
+ )}
433
+ </div>
434
+ )}
435
+ </form.Field>
436
+ ```
437
+
438
+ <DocMessage>
439
+ Gate the message on `field.state.meta.isTouched` if you only want it to appear after the user has visited the field.
440
+ </DocMessage>
441
+
442
+ ## Array fields
443
+
444
+ For a repeatable set of fields, such as environment variables, describe the item shape as an array in the schema and declare the field with `mode="array"`:
445
+
446
+ ```tsx title="schema" showLineNumbers
447
+ const schema = z.object({
448
+ envVars: z.array(
449
+ z.object({
450
+ key: z.string().min(1, 'Key is required.'),
451
+ value: z.string().min(1, 'Value is required.')
452
+ })
453
+ )
454
+ });
455
+ ```
456
+
457
+ An array field exposes `pushValue` and `removeValue`. Each input targets its row with a nested `form.Field` whose `name` includes the index:
458
+
459
+ ```tsx title="Array fields" showLineNumbers {1,4,17,20}
460
+ <form.Field name="envVars" mode="array">
461
+ {(arrayField) => (
462
+ <div className="flex flex-col gap-3">
463
+ {arrayField.state.value.map((_, i) => (
464
+ <div key={i} className="flex items-start gap-2">
465
+ <form.Field name={`envVars[${i}].key`}>{(field) => <InputText value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} placeholder="KEY" />}</form.Field>
466
+ <form.Field name={`envVars[${i}].value`}>{(field) => <InputText value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} placeholder="value" />}</form.Field>
467
+ <Button type="button" severity="secondary" variant="text" onClick={() => arrayField.removeValue(i)}>
468
+ <Times />
469
+ </Button>
470
+ </div>
471
+ ))}
472
+ <Button type="button" variant="outlined" onClick={() => arrayField.pushValue({ key: '', value: '' })}>
473
+ Add variable
474
+ </Button>
475
+ </div>
476
+ )}
477
+ </form.Field>
478
+ ```
479
+
480
+ ## Nested objects
481
+
482
+ Group related fields under an object in the schema and target them with a dotted `name`:
483
+
484
+ ```tsx title="schema"
485
+ const schema = z.object({
486
+ build: z.object({
487
+ command: z.string().min(1, 'Build command is required.'),
488
+ install: z.string().min(1, 'Install command is required.')
489
+ })
490
+ });
491
+ ```
492
+
493
+ ```tsx title="Nested fields"
494
+ <form.Field name="build.command">
495
+ {(field) => <InputText value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} placeholder="npm run build" />}
496
+ </form.Field>
497
+ <form.Field name="build.install">
498
+ {(field) => <InputText value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} placeholder="npm install" />}
499
+ </form.Field>
500
+ ```
501
+
502
+ Defaults follow the same shape: `defaultValues: { build: { command: '', install: '' } }`.