shadcn/Guides

Forms

Build forms with React and shadcn/ui.

formsreact-hook-formtanstack-formvalidation

Pick Your Framework

Start by selecting your framework. Then follow the instructions to learn how to build forms with shadcn/ui and the form library of your choice.


React Hook Form

Installation

npm install react-hook-form @hookform/resolvers zod

Add Components

npx shadcn@latest add form

Create a Form

import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"

const formSchema = z.object({
  username: z.string().min(2).max(50),
})

export function FormDemo() {
  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)}>
        <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>
  )
}

Form Components

The form component is built from the following components:

  • Form - Wrapper component that provides form context
  • FormField - Controlled form field component
  • FormItem - Container for form field components
  • FormLabel - Label for form field
  • FormControl - Control for form field (Input, Select, etc.)
  • FormDescription - Description for form field
  • FormMessage - Error message for form field
  • FormSuccess - Success message for form field

Usage with Input Components

import { Input } from "@/components/ui/input"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Textarea } from "@/components/ui/textarea"

<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 use MDX syntax for formatting.
      </FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>

TanStack Form

Installation

npm install @tanstack/react-form

Add Components

npx shadcn@latest add form

Create a Form

import { useForm } from "@tanstack/react-form"
import { zodValidator } from "@tanstack/zod-adapter"
import { z } from "zod"

const formSchema = z.object({
  username: z.string().min(2).max(50),
})

export function FormDemo() {
  const form = useForm({
    validatorAdapter: zodValidator(),
    defaultValues: {
      username: "",
    },
    onSubmit: async ({ value }) => {
      console.log(value)
    },
  })

  return (
    <form.Provider>
      <form
        onSubmit={(e) => {
          e.preventDefault()
          form.handleSubmit()
        }}
      >
        <form.Field
          name="username"
          children={(field) => (
            <div>
              <label htmlFor={field.name}>Username</label>
              <input
                id={field.name}
                name={field.name}
                value={field.state.value}
                onBlur={field.handleBlur}
                onChange={(e) => field.handleChange(e.target.value)}
              />
              {field.state.meta.touchedErrors && (
                <span>{field.state.meta.touchedErrors}</span>
              )}
            </div>
          )}
        />
        <button type="submit">Submit</button>
      </form>
    </form.Provider>
  )
}

Form Components

The form component is built from the following components:

  • Form - Provider component that provides form context
  • FormField - Controlled form field component
  • FormItem - Container for form field components
  • FormLabel - Label for form field
  • FormControl - Control for form field (Input, Select, etc.)
  • FormDescription - Description for form field
  • FormMessage - Error message for form field

Usage with UI Components

import { useForm } from "@tanstack/react-form"
import { zodValidator } from "@tanstack/zod-adapter"
import { z } from "zod"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"

<form.Field
  name="bio"
  children={(field) => (
    <FormItem>
      <FormLabel>Bio</FormLabel>
      <FormControl>
        <Textarea
          placeholder="Tell us a little bit about yourself"
          className="resize-none"
          value={field.state.value}
          onBlur={field.handleBlur}
          onChange={(e) => field.handleChange(e.target.value)}
        />
      </FormControl>
      <FormDescription>
        You can use MDX syntax for formatting.
      </FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>