Components
Form
A thin, accessible layer over react-hook-form that wires labels, controls, descriptions, and validation messages together with the correct ARIA relationships.
Basic usage
Spread the useForm() result onto Form, then drive each input through a FormField render prop.
Validation
Pass rules to a field and submit empty — FormMessage surfaces the error and the control flips to its invalid state.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
Form | FormProvider | — | Context provider — spread the object returned by useForm() onto it to wire the tree to react-hook-form. |
FormFieldrequired | ControllerProps | — | Connects a single field. Requires control and name; render receives a field object to spread onto your input. |
FormField.namerequired | string | — | The form field key registered with react-hook-form. |
FormField.controlrequired | Control | — | The control object from useForm() that the field binds to. |
FormField.renderrequired | ({ field }) => ReactNode | — | Render prop that returns the field UI; spread field onto the input. |
FormItem | React.ComponentProps<'div'> | — | Grid wrapper that scopes a unique id used to link label, control, description, and message. |
FormLabel | LabelPrimitive.Root | — | Label auto-linked to the control via htmlFor; turns destructive when the field has an error. |
FormControl | Slot | — | Slot that forwards id, aria-describedby, and aria-invalid onto its single input child. |
FormDescription | React.ComponentProps<'p'> | — | Muted helper text referenced by the control via aria-describedby. |
FormMessage | React.ComponentProps<'p'> | — | Renders the field's validation error, or children when there is no error. Renders nothing when empty. |
Accessibility
FormLabelsetshtmlForto the generated control id, so clicking the label focuses the input and screen readers announce the pairing.FormControlwiresaria-describedbyto the description and, when invalid, the error message — both are announced for the focused field.- When a field has an error, the control receives
aria-invalid="true"and the label turns destructive, conveying state beyond color alone. - Every id is derived from
React.useId()perFormItem, so labels and messages stay correctly associated even with many fields on the page.