This skill should be used when the user asks about "form validation", "react-hook-form", "zod schema", "form submission", "input validation", "form errors", "useForm hook", "form field", or mentions form handling, validation, or react-hook-form integration with shadcn.
View on GitHubplugins/shadcn-dev/skills/shadcn-forms/SKILL.md
February 2, 2026
Select agents to install to:
npx add-skill https://github.com/nthplusio/functional-claude/blob/main/plugins/shadcn-dev/skills/shadcn-forms/SKILL.md -a claude-code --skill shadcn-formsInstallation paths:
.claude/skills/shadcn-forms/# shadcn/ui Forms
Build validated forms with react-hook-form, zod, and shadcn/ui components.
## Setup
### Install Dependencies
```bash
npm install react-hook-form zod @hookform/resolvers
npx shadcn@latest add form input label
```
### Form Component Overview
shadcn's Form component wraps react-hook-form with accessible form fields:
- `Form` - FormProvider wrapper
- `FormField` - Controller wrapper
- `FormItem` - Field container
- `FormLabel` - Accessible label
- `FormControl` - Input wrapper
- `FormDescription` - Helper text
- `FormMessage` - Error message
## Basic Form Pattern
### 1. Define Zod Schema
```tsx
import { z } from "zod"
const formSchema = z.object({
username: z.string().min(2, "Username must be at least 2 characters"),
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
})
type FormValues = z.infer<typeof formSchema>
```
### 2. Create Form Component
```tsx
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
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 SignupForm() {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
username: "",
email: "",
password: "",
},
})
async function onSubmit(data: FormValues) {
console.log(data)
// Handle form submission
}
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="johndoe" {...field} />
<