Skip to content

Shadcn Form

The shadcn/ui Form connects React Hook Form and Zod to accessible, Tailwind-styled fields. It handles labels, descriptions, and validation messages with the right ARIA wiring, so you write less boilerplate and ship accessible forms. Reach for it whenever a form needs client-side validation and inline error messages.

Key features

  • Wraps React Hook Form with accessible field wiring.
  • Schema validation with Zod through the resolver.
  • Automatic labels, descriptions, and error messages with correct ARIA.
  • Works with Input, Select, checkbox, and other fields.
  • Swappable validators: Zod, Yup, Valibot, and more.

Installation

bash
npx shadcn@latest add form

This adds the Form parts and installs react-hook-form, zod, and the resolver.

Usage

tsx
"use client"

import { z } from "zod"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/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({
  username: z.string().min(2, "At least 2 characters."),
})

export function ProfileForm() {
  const form = useForm({
    resolver: zodResolver(schema),
    defaultValues: { username: "" },
  })

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

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <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>
  )
}

Anatomy

PartPurpose
FormProvider that shares the React Hook Form context.
FormFieldConnects a field to the form by name.
FormItemGroups a field's label, control, and message.
FormLabelAccessible label wired to the control.
FormControlWraps the input and forwards ARIA attributes.
FormDescriptionHelper text for the field.
FormMessageRenders the field's validation error.

Validation

Validation is schema-driven. Define a Zod schema, pass it through zodResolver, and FormMessage shows each error automatically with aria-invalid and aria-describedby set for you. Errors appear on submit and re-validate as the user corrects them.

Built on React Hook Form

The Form utilities wrap React Hook Form and are independent of the UI primitive layer. The fields you place inside (Input, Select, checkbox) follow their component APIs.

Accessibility

  • Every field gets a programmatically associated label, description, and error, so screen readers announce state changes.
  • Keep error messages specific and actionable ("Enter a valid email"), not generic ("Invalid input").
  • Preserve labels during submission; disable the submit Button and show a spinner rather than replacing the form.

When to use the Form

Use the Form component whenever a form needs validation, error messages, or more than a couple of fields: sign-in, sign-up, checkout, settings, and contact. For a single uncontrolled field with no validation, a bare Input is enough. For multi-step flows, drive several useForm steps and validate each before advancing.

ShadcnStore's form blocks ship the field layouts as plain, framework-agnostic markup so they drop into any stack. Wire them to this Form component when you want React Hook Form validation:

A Form composes Input and Select fields, submits with a Button, and often lives inside a Card or a Dialog.

FAQ

What is the shadcn form used for?

The Form component wires React Hook Form and Zod to shadcn fields, giving accessible labels, descriptions, and validation messages with minimal boilerplate.

Does shadcn form use React Hook Form and Zod?

Yes. It is a thin wrapper around React Hook Form, with Zod as the recommended schema validator through the resolver.

How does validation work in shadcn form?

Define a Zod schema, pass it to useForm via zodResolver, and FormMessage renders each field's error automatically with the correct ARIA wiring.

Can I use a validator other than Zod?

Yes. React Hook Form supports resolvers for Yup, Valibot, and others; swap the resolver and keep the same field structure.