Make your AI a shadcn expert

Shadcn Form

React form for settings, profiles, and sign-up. Built with TypeScript and Tailwind CSS for Next.js using react-hook-form — labels, errors, and Controller wiring.

Form is the React Hook Form provider plus the field parts. Spread useForm() onto Form, wrap a native <form>, and put each control inside FormField. Use it when a field needs a label, a description, and an error that stay wired to the same name.

Scroll to load preview...

Usage

import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)}>
    <FormField
      control={form.control}
      name="username"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Username</FormLabel>
          <FormControl>
            <Input placeholder="shadcn" {...field} />
          </FormControl>
          <FormDescription>Your public display name.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
  </form>
</Form>

Form is FormProvider. FormField is Controller. You still need the native <form> for submit.

Composition

FormLabel
FormControl
FormDescription
FormMessage

Profile

Username, email, bio. mode: "onChange" so each field validates as they type.

Scroll to load preview...

Checkbox

One name holds a string[]. Nested FormFields toggle ids in that array.

Scroll to load preview...

Select

Put FormControl on SelectTrigger. onValueChange writes the value — do not spread {...field} onto Select.

Scroll to load preview...

Combobox

Popover plus Command. form.setValue("language", …) from onSelect.

Scroll to load preview...

Date Picker

Calendar in a Popover. field.onChange is onSelect. The value is a Date.

Scroll to load preview...

API

Prop

Type

FormItem is a grid gap-2 wrapper. FormLabel, FormControl, FormDescription, and FormMessage take className. FormControl is a Slot — one child that can take a ref.

Notes

FormField is Controller

Do not wrap a second Controller. FormLabel, FormControl, and FormMessage read context from FormField — outside it, useFormField throws.

FormControl must have exactly one child. For Select, Checkbox, and Calendar, wire value / onChange yourself.

With other components

Questions

Was this page helpful?

Sign in to leave feedback.