Overview
- Form wraps `useForm` with context so nested fields can access `control`.
- FormField uses `Controller` to bind inputs to field names.
- FormControl augments inputs with `id`, `aria-describedby`, and `aria-invalid` automatically.
- FormMessage renders validation errors or custom fallback copy.
Example form
Combine with Pixexid inputs and buttons to deliver consistent validation feedback.
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import {
Form,
FormField,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
const schema = z.object({
projectName: z.string().min(2, "Project name must be at least 2 characters"),
email: z.string().email("Enter a valid email"),
})
type FormValues = z.infer<typeof schema>
export function CreateProjectForm() {
const form = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: {
projectName: "",
email: "",
},
})
return (
<Form {...form}>
<form className="space-y-6" onSubmit={form.handleSubmit(console.log)}>
<FormField
control={form.control}
name="projectName"
render={({ field }) => (
<FormItem>
<FormLabel>Project name</FormLabel>
<FormControl>
<Input placeholder="Pixexid Web" {...field} />
</FormControl>
<FormDescription>Shown in the project list.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Notification email</FormLabel>
<FormControl>
<Input type="email" placeholder="you@pixexid.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Create project</Button>
</form>
</Form>
)
}Key exports
| Name | Type | Description |
|---|---|---|
Form | FormProvider from react-hook-form | Wraps your form with context so `FormField` + hooks can access state. |
FormField | ControllerProps<TFieldValues, TName> | Binds a form control to a field name using React Hook Form Controller. |
FormItem | React.HTMLAttributes<HTMLDivElement> | Layout wrapper that generates unique IDs for label/description/message hooks. |
useFormField | () => { name, id, error, ... } | Hook used internally by `FormLabel`, `FormControl`, `FormMessage`, and `FormDescription`. |
Implementation tips
Best practices
- Call `form.handleSubmit` in `<form onSubmit>` to ensure validation runs.
- Pass `rules` or Zod resolvers to enforce constraints.
- Combine `FormDescription` + `FormMessage` for assistive descriptions.
Accessibility
- `FormLabel` attaches `htmlFor` automatically to the control.
- `FormMessage` uses `aria-describedby` to announce errors.
- Ensure `defaultValues` include every field to avoid uncontrolled warnings.