FormField
A react-hook-form helper that wires Field, label, description, and error to a Controller in one component
Installation
pnpm dlx shadcn@latest add https://prototyper-ui.com/r/form-field.jsonnpx shadcn@latest add https://prototyper-ui.com/r/form-field.jsonyarn dlx shadcn@latest add https://prototyper-ui.com/r/form-field.jsonbunx --bun shadcn@latest add https://prototyper-ui.com/r/form-field.jsonThis will add the following files to your project:
components/ui/form-field.tsx
Peer dependency: This component requires
react-hook-form. Install it alongside:npm install react-hook-form @hookform/resolvers zod
Note: This component depends on Field. It will be installed automatically.
Usage
import { useForm, FormProvider } from "react-hook-form"
import { FormField } from "@/components/ui/form-field"
import { Input } from "@/components/ui/input"
const form = useForm({ defaultValues: { email: "" } })
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField name="email" label="Email" required>
<Input type="email" placeholder="you@example.com" />
</FormField>
</form>
</FormProvider>FormField uses Controller + useFormContext internally, so it must be rendered inside a <FormProvider>. It auto-wires value, onChange, onBlur, and ref to the child input via cloneElement.
When to use FormField vs raw Field
Use FormField | Use raw Field + Controller |
|---|---|
| Standard text inputs, textareas | Select, NumberField, Checkbox, Switch, RadioGroup |
| Quick forms with minimal boilerplate | Components that use onValueChange / onCheckedChange |
Inputs accepting value + onChange | Custom controlled components |
For components with non-standard change handlers, use Controller directly with Field as shown in the Forms guide.
Examples
Validation
All Input Types
Dynamic Fields
Multi-Step Form
Styling
Data Slots
Use data-slot attributes to target specific parts of the component:
| Slot name | Element |
|---|---|
form-field | Root Field wrapper |
field-label | Label element |
field-description | Description paragraph |
field-error | Error message container |
Customization Examples
/* Increase spacing between form fields */
[data-slot="form-field"] {
@apply gap-2;
}{
/* Override width via className */
}
<FormField name="email" label="Email" className="max-w-xs">
<Input />
</FormField>;API Reference
FormField
A helper component that wires a Controller to Field + FieldLabel + FieldDescription + FieldError.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | - | Field name matching the form schema |
label | string | - | Label text displayed above the input |
description | string | - | Help text displayed below the label |
required | boolean | - | Shows a required indicator on the label |
className | string | - | Additional CSS classes on the root Field |
children | React.ReactElement | - | The input component to wire up |
Accessibility
Keyboard Interactions
| Key | Action |
|---|---|
Tab | Moves focus to the input within the field |
ARIA Attributes
- The
Fieldwrapper renders withrole="group". FieldLabelis associated with the input via Base UI's label mechanism.FieldErrorrenders withrole="alert"andaria-live="polite"for screen reader announcements.- When
invalidis true,data-invalidis set on the field for styling hooks.