@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,503 @@
1
+ # React Hook Form
2
+
3
+ Build validated forms with PrimeReact and React Hook Form.
4
+
5
+ <DocMessage>
6
+ Open the <a href="https://stackblitz.com/edit/vitejs-vite-jkwqpcwm?file=src%2Fcomponents%2Frhf-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
+ [React Hook Form](https://react-hook-form.com/) manages form state, submission and validation with minimal re-renders. PrimeReact inputs are controlled, so they connect to the form through its `Controller` component.
12
+
13
+ Throughout this guide validation is handled with [Zod](https://zod.dev/): you describe the form once as a schema and React Hook Form enforces it on every change and submit.
14
+
15
+ ```bash
16
+ npm install react-hook-form zod @hookform/resolvers
17
+ ```
18
+
19
+ ## Anatomy
20
+
21
+ A field is a `Controller` wrapped around an input. The `Controller` owns the value in the form state and hands it to the input through its `render` callback:
22
+
23
+ ```tsx title="Anatomy" showLineNumbers
24
+ <Controller
25
+ name="projectName" // path of this field in the form data
26
+ control={control} // the instance returned by useForm
27
+ render={({ field, fieldState }) => (
28
+ <InputText
29
+ {...field} // value, onChange, onBlur, name, ref
30
+ invalid={fieldState.invalid} // error styling
31
+ />
32
+ )}
33
+ />
34
+ ```
35
+
36
+ - **`field`**: the value and handlers that bind the input to the form (`value`, `onChange`, `onBlur`, `name`, `ref`).
37
+ - **`fieldState`**: the validation state of this field (`error`, `invalid`, `isTouched`, `isDirty`).
38
+
39
+ Spreading `{...field}` is enough for native inputs like `InputText` and `Textarea`. Other components need their change forwarded explicitly, which is covered in [Fields](#fields).
40
+
41
+ ## Create the form
42
+
43
+ ### Schema
44
+
45
+ Describe the shape and rules of the form with Zod. The message passed to each rule is what surfaces as the field error:
46
+
47
+ ```tsx title="schema.ts" showLineNumbers
48
+ import { z } from 'zod';
49
+
50
+ export const schema = z.object({
51
+ projectName: z.string().min(1, 'Project name is required.'),
52
+ framework: z.string().min(1, 'Please select a framework.'),
53
+ rootDir: z.string().min(1, 'Root directory is required.'),
54
+ environments: z.array(z.string()).min(1, 'Select at least one environment.')
55
+ });
56
+
57
+ export type FormValues = z.infer<typeof schema>;
58
+ ```
59
+
60
+ ### Connect to React Hook Form
61
+
62
+ Pass the schema to `useForm` through `zodResolver`, and provide `defaultValues` for every field so the inputs are controlled from the first render:
63
+
64
+ ```tsx title="deploy-form.tsx" showLineNumbers {6}
65
+ import { useForm } from 'react-hook-form';
66
+ import { zodResolver } from '@hookform/resolvers/zod';
67
+ import { schema, type FormValues } from './schema';
68
+
69
+ const { control, handleSubmit } = useForm<FormValues>({
70
+ resolver: zodResolver(schema),
71
+ defaultValues: { projectName: '', framework: '', rootDir: './', environments: [] }
72
+ });
73
+ ```
74
+
75
+ <DocMessage>
76
+ `zodResolver` is used here, but `@hookform/resolvers` also ships resolvers for Yup, Valibot, Joi and more. Swap the resolver and keep everything else the same.
77
+ </DocMessage>
78
+
79
+ ### Submit
80
+
81
+ Wrap your handler with `handleSubmit`. It validates first and only calls your callback when every field passes; the `values` argument is fully typed from the schema:
82
+
83
+ ```tsx title="Submit" showLineNumbers
84
+ const onSubmit = handleSubmit((values) => {
85
+ console.log(values);
86
+ });
87
+
88
+ return (
89
+ <form onSubmit={onSubmit} className="flex flex-col gap-6">
90
+ {/* fields go here */}
91
+ <Button type="submit">Deploy</Button>
92
+ </form>
93
+ );
94
+ ```
95
+
96
+ ### Reset
97
+
98
+ Pull `reset` from `useForm`. With no argument it clears every field back to `defaultValues`; pass an object to seed the form with new values instead, for example after a successful submit:
99
+
100
+ ```tsx title="Reset"
101
+ const { control, handleSubmit, reset } = useForm({/* ... */});
102
+
103
+ // restore the defaults
104
+ <Button type="button" severity="secondary" variant="outlined" onClick={() => reset()}>
105
+ Reset
106
+ </Button>;
107
+
108
+ // or set new values
109
+ reset({ projectName: 'my-app', framework: 'nextjs', environments: ['production'] });
110
+ ```
111
+
112
+ ### Result
113
+
114
+ Everything above comes together as the complete form. Each field is broken down in [Fields](#fields):
115
+
116
+ <div className="[&_pre]:max-h-[32rem] [&_pre]:overflow-y-auto">
117
+
118
+ ```tsx title="deploy-form.tsx" showLineNumbers
119
+ 'use client';
120
+ import { useForm, Controller } from 'react-hook-form';
121
+ import { zodResolver } from '@hookform/resolvers/zod';
122
+ import { z } from 'zod';
123
+ import { ChevronDown, Check } from '@primeicons/react';
124
+ import { InputText } from '@primereact/ui/inputtext';
125
+ import { Select } from '@primereact/ui/select';
126
+ import { Checkbox } from '@primereact/ui/checkbox';
127
+ import { CheckboxGroup } from '@primereact/ui/checkboxgroup';
128
+ import { Label } from '@primereact/ui/label';
129
+ import { Button } from '@primereact/ui/button';
130
+ import { Message } from '@primereact/ui/message';
131
+
132
+ const FRAMEWORKS = [
133
+ { label: 'Next.js', value: 'nextjs' },
134
+ { label: 'Vite', value: 'vite' },
135
+ { label: 'Astro', value: 'astro' }
136
+ ];
137
+
138
+ const ENVIRONMENTS = [
139
+ { label: 'Production', value: 'production' },
140
+ { label: 'Preview', value: 'preview' },
141
+ { label: 'Development', value: 'development' }
142
+ ];
143
+
144
+ const schema = z.object({
145
+ projectName: z.string().min(1, 'Project name is required.'),
146
+ framework: z.string().min(1, 'Please select a framework.'),
147
+ rootDir: z.string().min(1, 'Root directory is required.'),
148
+ environments: z.array(z.string()).min(1, 'Select at least one environment.')
149
+ });
150
+
151
+ type FormValues = z.infer<typeof schema>;
152
+
153
+ export default function DeployForm() {
154
+ const { control, handleSubmit, reset } = useForm<FormValues>({
155
+ resolver: zodResolver(schema),
156
+ defaultValues: { projectName: '', framework: '', rootDir: './', environments: [] }
157
+ });
158
+
159
+ const onSubmit = handleSubmit((values) => {
160
+ console.log(values);
161
+ });
162
+
163
+ return (
164
+ <form onSubmit={onSubmit} className="flex flex-col gap-6">
165
+ <Controller
166
+ name="projectName"
167
+ control={control}
168
+ render={({ field, fieldState }) => (
169
+ <div className="flex flex-col gap-2">
170
+ <Label htmlFor="projectName">Project name</Label>
171
+ <InputText id="projectName" {...field} invalid={fieldState.invalid} fluid />
172
+ {fieldState.error && (
173
+ <Message.Root severity="error" variant="simple" size="small">
174
+ <Message.Content>
175
+ <Message.Text>{fieldState.error.message}</Message.Text>
176
+ </Message.Content>
177
+ </Message.Root>
178
+ )}
179
+ </div>
180
+ )}
181
+ />
182
+
183
+ <Controller
184
+ name="framework"
185
+ control={control}
186
+ render={({ field, fieldState }) => (
187
+ <div className="flex flex-col gap-2">
188
+ <Label htmlFor="framework">Framework preset</Label>
189
+ <Select.Root value={field.value} onValueChange={(e) => field.onChange(e.value)} options={FRAMEWORKS} optionLabel="label" optionValue="value" invalid={fieldState.invalid}>
190
+ <Select.Trigger type="button">
191
+ <Select.Value placeholder="Select a framework" />
192
+ <Select.Indicator>
193
+ <ChevronDown />
194
+ </Select.Indicator>
195
+ </Select.Trigger>
196
+ <Select.Portal>
197
+ <Select.Positioner>
198
+ <Select.Popup>
199
+ <Select.List />
200
+ </Select.Popup>
201
+ </Select.Positioner>
202
+ </Select.Portal>
203
+ </Select.Root>
204
+ {fieldState.error && (
205
+ <Message.Root severity="error" variant="simple" size="small">
206
+ <Message.Content>
207
+ <Message.Text>{fieldState.error.message}</Message.Text>
208
+ </Message.Content>
209
+ </Message.Root>
210
+ )}
211
+ </div>
212
+ )}
213
+ />
214
+
215
+ <Controller
216
+ name="rootDir"
217
+ control={control}
218
+ render={({ field, fieldState }) => (
219
+ <div className="flex flex-col gap-2">
220
+ <Label htmlFor="rootDir">Root directory</Label>
221
+ <InputText id="rootDir" {...field} invalid={fieldState.invalid} fluid />
222
+ {fieldState.error && (
223
+ <Message.Root severity="error" variant="simple" size="small">
224
+ <Message.Content>
225
+ <Message.Text>{fieldState.error.message}</Message.Text>
226
+ </Message.Content>
227
+ </Message.Root>
228
+ )}
229
+ </div>
230
+ )}
231
+ />
232
+
233
+ <Controller
234
+ name="environments"
235
+ control={control}
236
+ render={({ field, fieldState }) => (
237
+ <div className="flex flex-col gap-2">
238
+ <Label>Environments</Label>
239
+ <CheckboxGroup value={field.value} onValueChange={(e) => field.onChange(e.value)}>
240
+ {ENVIRONMENTS.map((env) => (
241
+ <div key={env.value} className="flex items-center gap-2">
242
+ <Checkbox.Root inputId={env.value} value={env.value}>
243
+ <Checkbox.Box>
244
+ <Checkbox.Indicator match="checked">
245
+ <Check />
246
+ </Checkbox.Indicator>
247
+ </Checkbox.Box>
248
+ </Checkbox.Root>
249
+ <Label htmlFor={env.value}>{env.label}</Label>
250
+ </div>
251
+ ))}
252
+ </CheckboxGroup>
253
+ {fieldState.error && (
254
+ <Message.Root severity="error" variant="simple" size="small">
255
+ <Message.Content>
256
+ <Message.Text>{fieldState.error.message}</Message.Text>
257
+ </Message.Content>
258
+ </Message.Root>
259
+ )}
260
+ </div>
261
+ )}
262
+ />
263
+
264
+ <div className="flex justify-end gap-3">
265
+ <Button type="button" severity="secondary" variant="outlined" onClick={() => reset()}>
266
+ Reset
267
+ </Button>
268
+ <Button type="submit">Deploy</Button>
269
+ </div>
270
+ </form>
271
+ );
272
+ }
273
+ ```
274
+
275
+ </div>
276
+
277
+ ## Fields
278
+
279
+ Every input lives inside a `Controller`. How you forward the change depends on the component:
280
+
281
+ - **Native inputs**: `InputText` and `Textarea` render a real `<input>` / `<textarea>`, so spread `{...field}` (or pass `field.onChange` directly).
282
+ - **Composite inputs**: `Select`, `Checkbox`, `RadioButtonGroup` and `CheckboxGroup` report changes through `onValueChange` / `onCheckedChange` with an event object, so forward `event.value` / `event.checked`.
283
+
284
+ Bind `invalid={fieldState.invalid}` on any component to get error styling.
285
+
286
+ ### InputText
287
+
288
+ ```tsx title="InputText"
289
+ <Controller
290
+ name="projectName"
291
+ control={control}
292
+ render={({ field, fieldState }) => (
293
+ <div className="flex flex-col gap-2">
294
+ <Label htmlFor="projectName">Project name</Label>
295
+ <InputText id="projectName" {...field} invalid={fieldState.invalid} fluid />
296
+ </div>
297
+ )}
298
+ />
299
+ ```
300
+
301
+ ### Select
302
+
303
+ ```tsx title="Select"
304
+ <Controller
305
+ name="framework"
306
+ control={control}
307
+ render={({ field, fieldState }) => (
308
+ <Select.Root value={field.value} onValueChange={(e) => field.onChange(e.value)} options={FRAMEWORKS} optionLabel="label" optionValue="value" invalid={fieldState.invalid}>
309
+ <Select.Trigger type="button">
310
+ <Select.Value placeholder="Select a framework" />
311
+ <Select.Indicator>
312
+ <ChevronDown />
313
+ </Select.Indicator>
314
+ </Select.Trigger>
315
+ <Select.Portal>
316
+ <Select.Positioner>
317
+ <Select.Popup>
318
+ <Select.List />
319
+ </Select.Popup>
320
+ </Select.Positioner>
321
+ </Select.Portal>
322
+ </Select.Root>
323
+ )}
324
+ />
325
+ ```
326
+
327
+ ### Checkbox
328
+
329
+ A single checkbox is a boolean, so bind `checked` and forward `event.checked`:
330
+
331
+ ```tsx title="Checkbox"
332
+ <Controller
333
+ name="agree"
334
+ control={control}
335
+ render={({ field }) => (
336
+ <Checkbox.Root checked={field.value} onCheckedChange={(e) => field.onChange(e.checked)}>
337
+ <Checkbox.Box>
338
+ <Checkbox.Indicator match="checked">
339
+ <Check />
340
+ </Checkbox.Indicator>
341
+ </Checkbox.Box>
342
+ </Checkbox.Root>
343
+ )}
344
+ />
345
+ ```
346
+
347
+ ### Groups
348
+
349
+ `RadioButtonGroup`, `CheckboxGroup` and `ToggleButtonGroup` own a single value for the whole group, so wrap the group (not each item) in one `Controller`:
350
+
351
+ ```tsx title="CheckboxGroup"
352
+ <Controller
353
+ name="environments"
354
+ control={control}
355
+ render={({ field }) => (
356
+ <CheckboxGroup value={field.value} onValueChange={(e) => field.onChange(e.value)}>
357
+ {ENVIRONMENTS.map((env) => (
358
+ <div key={env.value} className="flex items-center gap-2">
359
+ <Checkbox.Root inputId={env.value} value={env.value}>
360
+ <Checkbox.Box>
361
+ <Checkbox.Indicator match="checked">
362
+ <Check />
363
+ </Checkbox.Indicator>
364
+ </Checkbox.Box>
365
+ </Checkbox.Root>
366
+ <Label htmlFor={env.value}>{env.label}</Label>
367
+ </div>
368
+ ))}
369
+ </CheckboxGroup>
370
+ )}
371
+ />
372
+ ```
373
+
374
+ ### Value types
375
+
376
+ Most inputs hold a string, but some do not. Match the schema and the empty `defaultValue` to the value type:
377
+
378
+ - `InputNumber`, `Slider`, `Rating` → `number` (`z.number()`)
379
+ - `DatePicker` → `Date` (`z.date()`)
380
+ - `Checkbox`, `ToggleSwitch`, `ToggleButton` → `boolean` (`z.boolean()`)
381
+ - `CheckboxGroup`, multiple `Select`, `InputTags` → `array` (`z.array(...)`)
382
+
383
+ <DocMessage>
384
+ Number and date fields start as `null`, not `''`. An empty string breaks their value type.
385
+ </DocMessage>
386
+
387
+ ## Validation
388
+
389
+ ### When it runs
390
+
391
+ By default the form validates on submit and then re-validates a field on every change. Change this with `mode`:
392
+
393
+ ```tsx
394
+ useForm({ mode: 'onBlur', resolver: zodResolver(schema) });
395
+ ```
396
+
397
+ | Mode | Validates |
398
+ | ---------------------- | -------------------------------------- |
399
+ | `onSubmit` _(default)_ | on submit, then re-validates on change |
400
+ | `onBlur` | when a field loses focus |
401
+ | `onChange` | on every keystroke / change |
402
+ | `onTouched` | on first blur, then on every change |
403
+ | `all` | on both blur and change |
404
+
405
+ `reValidateMode` (default `onChange`) controls how fields re-validate _after_ the first submit.
406
+
407
+ ### Showing errors
408
+
409
+ `fieldState.error.message` holds the message resolved from the schema. Render it with the `Message` component in the `simple` variant so it sits inline under the field:
410
+
411
+ ```tsx title="Error message"
412
+ <Controller
413
+ name="projectName"
414
+ control={control}
415
+ render={({ field, fieldState }) => (
416
+ <div className="flex flex-col gap-2">
417
+ <Label htmlFor="projectName">Project name</Label>
418
+ <InputText id="projectName" {...field} invalid={fieldState.invalid} fluid />
419
+ {fieldState.error && (
420
+ <Message.Root severity="error" variant="simple" size="small">
421
+ <Message.Content>
422
+ <Message.Text>{fieldState.error.message}</Message.Text>
423
+ </Message.Content>
424
+ </Message.Root>
425
+ )}
426
+ </div>
427
+ )}
428
+ />
429
+ ```
430
+
431
+ ## Array fields
432
+
433
+ For a repeatable set of fields, such as environment variables, describe the item shape as an array in the schema and drive the rows with `useFieldArray`:
434
+
435
+ ```tsx title="schema" showLineNumbers
436
+ const schema = z.object({
437
+ envVars: z.array(
438
+ z.object({
439
+ key: z.string().min(1, 'Key is required.'),
440
+ value: z.string().min(1, 'Value is required.')
441
+ })
442
+ )
443
+ });
444
+ ```
445
+
446
+ `useFieldArray` returns the current rows plus helpers to add and remove them. Each input targets its row with a dotted `name` (`envVars.0.key`):
447
+
448
+ ```tsx title="Array fields" showLineNumbers {1,7,8}
449
+ const { fields, append, remove } = useFieldArray({ control, name: 'envVars' });
450
+
451
+ return (
452
+ <div className="flex flex-col gap-3">
453
+ {fields.map((row, i) => (
454
+ <div key={row.id} className="flex items-start gap-2">
455
+ <Controller name={`envVars.${i}.key`} control={control} render={({ field, fieldState }) => <InputText {...field} invalid={fieldState.invalid} placeholder="KEY" />} />
456
+ <Controller name={`envVars.${i}.value`} control={control} render={({ field, fieldState }) => <InputText {...field} invalid={fieldState.invalid} placeholder="value" />} />
457
+ <Button type="button" severity="secondary" variant="text" onClick={() => remove(i)}>
458
+ <Times />
459
+ </Button>
460
+ </div>
461
+ ))}
462
+ <Button type="button" variant="outlined" onClick={() => append({ key: '', value: '' })}>
463
+ Add variable
464
+ </Button>
465
+ </div>
466
+ );
467
+ ```
468
+
469
+ <DocMessage>
470
+ Use `row.id` from `fields` as the React `key`, not the array index. `useFieldArray` keeps these ids stable across add and remove.
471
+ </DocMessage>
472
+
473
+ ## Nested objects
474
+
475
+ Group related fields under an object in the schema and target them with a dotted `name`:
476
+
477
+ ```tsx title="schema"
478
+ const schema = z.object({
479
+ build: z.object({
480
+ command: z.string().min(1, 'Build command is required.'),
481
+ install: z.string().min(1, 'Install command is required.')
482
+ })
483
+ });
484
+ ```
485
+
486
+ ```tsx title="Nested fields"
487
+ <Controller
488
+ name="build.command"
489
+ control={control}
490
+ render={({ field, fieldState }) => (
491
+ <InputText {...field} invalid={fieldState.invalid} placeholder="npm run build" />
492
+ )}
493
+ />
494
+ <Controller
495
+ name="build.install"
496
+ control={control}
497
+ render={({ field, fieldState }) => (
498
+ <InputText {...field} invalid={fieldState.invalid} placeholder="npm install" />
499
+ )}
500
+ />
501
+ ```
502
+
503
+ Defaults follow the same shape: `defaultValues: { build: { command: '', install: '' } }`.