> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/shadcn-ui/ui/llms.txt
> Use this file to discover all available pages before exploring further.

# Form

> Building forms with React Hook Form and Zod.

## Installation

The Form component is built on top of [React Hook Form](https://react-hook-form.com/) and [Zod](https://zod.dev/) for schema validation.

<CodeGroup>
  ```bash npm theme={null}
  npm install react-hook-form @hookform/resolvers zod
  ```

  ```bash pnpm theme={null}
  pnpm add react-hook-form @hookform/resolvers zod
  ```

  ```bash yarn theme={null}
  yarn add react-hook-form @hookform/resolvers zod
  ```

  ```bash bun theme={null}
  bun add react-hook-form @hookform/resolvers zod
  ```
</CodeGroup>

Or use the CLI:

```bash theme={null}
npx shadcn@latest add form
```

## Usage

```tsx theme={null}
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
```

### Create a form schema

Define your form schema using Zod:

```tsx theme={null}
import { z } from "zod"

const formSchema = z.object({
  username: z.string().min(2, {
    message: "Username must be at least 2 characters.",
  }),
})
```

### Define a form

Use the `useForm` hook from React Hook Form to create a form:

```tsx theme={null}
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"

const formSchema = z.object({
  username: z.string().min(2, {
    message: "Username must be at least 2 characters.",
  }),
})

export function ProfileForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      username: "",
    },
  })

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }
}
```

### Build your form

Compose form fields using the Form components:

```tsx theme={null}
import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"

export function ProfileForm() {
  // ...

  return (
    <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="shadcn" {...field} />
              </FormControl>
              <FormDescription>
                This is your public display name.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}
```

## Component API

### Form

The root form provider built on React Hook Form's `FormProvider`.

**Props:**

* All props from React Hook Form's `FormProvider`

### FormField

A controlled form field.

**Props:**

* `control` - Form control from `useForm`
* `name` - Field name
* `render` - Render function that receives field props

### FormItem

Container for a form field.

### FormLabel

Label for a form field.

**Props:**

* Automatically shows error state

### FormControl

Wrapper for the form control element.

**Props:**

* Automatically handles `id`, `aria-describedby`, and `aria-invalid`

### FormDescription

Description text for a form field.

### FormMessage

Displays form field errors.

**Props:**

* Automatically displays the error message for the field

### useFormField

A custom hook to access form field context.

**Returns:**

* `id` - Field ID
* `name` - Field name
* `formItemId` - Form item ID
* `formDescriptionId` - Description ID
* `formMessageId` - Message ID
* `error` - Field error
* `invalid` - Whether field is invalid
* `isDirty` - Whether field is dirty
* `isTouched` - Whether field is touched

## Examples

### Input

A simple form with an input field:

```tsx theme={null}
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).max(50),
})

export function InputForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      username: "",
    },
  })

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }

  return (
    <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="shadcn" {...field} />
              </FormControl>
              <FormDescription>
                This is your public display name.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}
```

### Textarea

A form with a textarea:

```tsx theme={null}
import { Textarea } from "@/components/ui/textarea"

const formSchema = z.object({
  bio: z
    .string()
    .min(10, {
      message: "Bio must be at least 10 characters.",
    })
    .max(160, {
      message: "Bio must not be longer than 160 characters.",
    }),
})

// In your form:
<FormField
  control={form.control}
  name="bio"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Bio</FormLabel>
      <FormControl>
        <Textarea
          placeholder="Tell us a little bit about yourself"
          className="resize-none"
          {...field}
        />
      </FormControl>
      <FormDescription>
        You can <span>@mention</span> other users and organizations.
      </FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>
```

### Checkbox

A form with a checkbox:

```tsx theme={null}
import { Checkbox } from "@/components/ui/checkbox"

const formSchema = z.object({
  mobile: z.boolean().default(false).optional(),
})

// In your form:
<FormField
  control={form.control}
  name="mobile"
  render={({ field }) => (
    <FormItem className="flex flex-row items-start space-x-3 space-y-0">
      <FormControl>
        <Checkbox
          checked={field.value}
          onCheckedChange={field.onChange}
        />
      </FormControl>
      <div className="space-y-1 leading-none">
        <FormLabel>
          Use different settings for my mobile devices
        </FormLabel>
        <FormDescription>
          You can manage your mobile notifications in the mobile settings page.
        </FormDescription>
      </div>
    </FormItem>
  )}
/>
```

### Select

A form with a select:

```tsx theme={null}
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

const formSchema = z.object({
  email: z
    .string({
      required_error: "Please select an email to display.",
    })
    .email(),
})

// In your form:
<FormField
  control={form.control}
  name="email"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <Select onValueChange={field.onChange} defaultValue={field.value}>
        <FormControl>
          <SelectTrigger>
            <SelectValue placeholder="Select a verified email to display" />
          </SelectTrigger>
        </FormControl>
        <SelectContent>
          <SelectItem value="m@example.com">m@example.com</SelectItem>
          <SelectItem value="m@google.com">m@google.com</SelectItem>
          <SelectItem value="m@support.com">m@support.com</SelectItem>
        </SelectContent>
      </Select>
      <FormDescription>
        You can manage email addresses in your email settings.
      </FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>
```

### Radio Group

A form with a radio group:

```tsx theme={null}
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"

const formSchema = z.object({
  type: z.enum(["all", "mentions", "none"], {
    required_error: "You need to select a notification type.",
  }),
})

// In your form:
<FormField
  control={form.control}
  name="type"
  render={({ field }) => (
    <FormItem className="space-y-3">
      <FormLabel>Notify me about...</FormLabel>
      <FormControl>
        <RadioGroup
          onValueChange={field.onChange}
          defaultValue={field.value}
          className="flex flex-col space-y-1"
        >
          <FormItem className="flex items-center space-x-3 space-y-0">
            <FormControl>
              <RadioGroupItem value="all" />
            </FormControl>
            <FormLabel className="font-normal">
              All new messages
            </FormLabel>
          </FormItem>
          <FormItem className="flex items-center space-x-3 space-y-0">
            <FormControl>
              <RadioGroupItem value="mentions" />
            </FormControl>
            <FormLabel className="font-normal">
              Direct messages and mentions
            </FormLabel>
          </FormItem>
          <FormItem className="flex items-center space-x-3 space-y-0">
            <FormControl>
              <RadioGroupItem value="none" />
            </FormControl>
            <FormLabel className="font-normal">Nothing</FormLabel>
          </FormItem>
        </RadioGroup>
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>
```

### Switch

A form with a switch:

```tsx theme={null}
import { Switch } from "@/components/ui/switch"

const formSchema = z.object({
  marketing_emails: z.boolean().default(false).optional(),
})

// In your form:
<FormField
  control={form.control}
  name="marketing_emails"
  render={({ field }) => (
    <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
      <div className="space-y-0.5">
        <FormLabel className="text-base">
          Marketing emails
        </FormLabel>
        <FormDescription>
          Receive emails about new products, features, and more.
        </FormDescription>
      </div>
      <FormControl>
        <Switch
          checked={field.value}
          onCheckedChange={field.onChange}
        />
      </FormControl>
    </FormItem>
  )}
/>
```

## Accessibility

* Built on React Hook Form for performance
* Automatic error handling and display
* Proper ARIA attributes
* Label associations
* Error announcements for screen readers

## API Reference

See the [React Hook Form](https://react-hook-form.com/) and [Zod](https://zod.dev/) documentation for complete API details.
