Installation
pnpm dlx shadcn@latest add https://neobrutalism.dev/r/form.jsonUsage
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'const formSchema = z.object({
username: z.string().min(2, {
message: 'Username must be at least 2 characters.',
}),
})
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: "",
},
});
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values);
}<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="ekmas" {...field} />
</FormControl>
<FormDescription>This is your public display name.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>Examples
Default
Basic
A simple form with a text input and a textarea. On submit, the form data is validated against a Zod schema and any errors are displayed next to each field.
Input
For input fields, spread the field object onto the <Input /> component. Wrapping it in <FormControl /> wires up the id, aria-describedby and aria-invalid attributes, and <FormMessage /> shows the validation error.
Textarea
For textarea fields, spread the field object onto the <Textarea /> component inside <FormControl />.
Select
For select components, use field.value and field.onChange on the <Select /> component and wrap the <SelectTrigger /> in <FormControl />. Pass items to <Select /> so <SelectValue /> renders the label instead of the raw value.
Checkbox
For checkbox arrays, use field.value and onCheckedChange with array manipulation. Give each <Checkbox /> its own <FormItem /> and <FormControl /> so its label and error state are wired up.
Radio Group
For radio groups, use field.value and onValueChange on the <RadioGroup /> component. Each <RadioGroupItem /> gets its own <FormItem /> and <FormControl />.
Switch
For switches, use field.value and onCheckedChange on the <Switch /> component.
Complex Forms
Here is an example of a more complex form with multiple fields and validation.
Array Fields
React Hook Form provides a useFieldArray hook for managing dynamic array fields. This is useful when you need to add or remove fields dynamically.