home / skills / doanchienthangdev / omgkit / shadcn-ui
This skill helps you build accessible UIs with shadcn/ui, Radix primitives, and React Hook Form for forms, dialogs, and composable components.
npx playbooks add skill doanchienthangdev/omgkit --skill shadcn-uiReview the files below or copy the command above to add this skill to your agents.
---
name: building-with-shadcn
description: Claude builds accessible React UIs using shadcn/ui components with Radix primitives and React Hook Form integration. Use when creating forms, dialogs, or composable UI systems.
---
# Building with shadcn/ui
## Quick Start
```bash
# Initialize and add components
npx shadcn-ui@latest init
npx shadcn-ui@latest add button card form input dialog
```
```tsx
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export function Example() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent className="flex gap-4">
<Button>Primary</Button>
<Button variant="outline">Outline</Button>
</CardContent>
</Card>
);
}
```
## Features
| Feature | Description | Guide |
|---------|-------------|-------|
| Button Variants | default, secondary, destructive, outline, ghost, link | `ref/button.md` |
| Form Integration | React Hook Form + Zod validation pattern | `ref/forms.md` |
| Dialog/Sheet | Modal dialogs and slide-out panels | `ref/dialogs.md` |
| Data Display | Table, Tabs, Accordion components | `ref/data-display.md` |
| Navigation | DropdownMenu, Command palette, NavigationMenu | `ref/navigation.md` |
| Feedback | Toast notifications with useToast hook | `ref/toast.md` |
## Common Patterns
### Form with Validation
```tsx
const formSchema = z.object({
email: z.string().email("Invalid email"),
name: z.string().min(2, "Name must be at least 2 characters"),
});
export function ProfileForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: { email: "", name: "" },
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField control={form.control} name="email" render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="name" render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<Button type="submit" disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? "Saving..." : "Save"}
</Button>
</form>
</Form>
);
}
```
### Dialog with Form
```tsx
export function EditDialog({ onSave }: { onSave: (data: Data) => void }) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Edit Profile</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Profile</DialogTitle>
<DialogDescription>Update your profile information.</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">Name</Label>
<Input id="name" className="col-span-3" />
</div>
</div>
<DialogFooter>
<DialogClose asChild><Button variant="outline">Cancel</Button></DialogClose>
<Button onClick={() => onSave(data)}>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
```
### Toast Notifications
```tsx
import { useToast } from "@/components/ui/use-toast";
export function SaveButton() {
const { toast } = useToast();
const handleSave = async () => {
try {
await saveData();
toast({ title: "Success", description: "Changes saved." });
} catch {
toast({ variant: "destructive", title: "Error", description: "Failed to save." });
}
};
return <Button onClick={handleSave}>Save</Button>;
}
```
## Best Practices
| Do | Avoid |
|----|-------|
| Install only components you need | Modifying generated component files directly |
| Use `cn()` utility for class merging | Skipping form validation |
| Extend components with composition | Overriding styles without good reason |
| Follow React Hook Form patterns | Using inline styles |
| Use TypeScript for type safety | Skipping loading and error states |
| Test component accessibility | Ignoring keyboard navigation |
This skill builds accessible React UIs using shadcn/ui components, Radix primitives, and React Hook Form integration. It focuses on composable building blocks like buttons, cards, dialogs, forms, and toasts to accelerate production-ready interfaces. The goal is predictable, accessible components with sensible defaults and easy extensibility.
Install the shadcn/ui initializer and add only the components you need. Components are provided as composable primitives (Button, Card, Dialog, Form, Input, Toast, etc.) wired to Radix accessibility patterns and utilities like cn() for class merging. Forms use React Hook Form plus Zod for validation and error handling, and UI primitives include helpers for dialogs, sheets, and notifications.
Do I need to install everything from shadcn/ui?
No. Add only the components you plan to use to reduce bundle size and keep the codebase focused.
How are forms validated?
Forms integrate with React Hook Form and typically use Zod schemas via a resolver for type-safe validation and clear error messages.