---
name: shadcn
displayName: shadcn/ui
description: shadcn/ui component library patterns with Radix UI primitives and Tailwind CSS. Use when creating tables, forms, dialogs, cards, buttons, or any UI component using shadcn/ui, installing shadcn components, or styling with shadcn patterns.
version: 1.0.0
---
# shadcn/ui Development Guidelines
Best practices for using shadcn/ui components with Tailwind CSS and Radix UI primitives.
## Core Principles
1. **Copy, Don't Install**: Components are copied to your project, not installed as dependencies
2. **Customizable**: Modify components directly in your codebase
3. **Accessible**: Built on Radix UI primitives with ARIA support
4. **Type-Safe**: Full TypeScript support
5. **Composable**: Build complex UIs from simple primitives
## Installation
### Initial Setup
```bash
npx shadcn@latest init
```
### Add Components
```bash
# Add individual components
npx shadcn@latest add button
npx shadcn@latest add form
npx shadcn@latest add dialog
# Add multiple
npx shadcn@latest add button card dialog
```
### Troubleshooting
#### npm Cache Errors (ENOTEMPTY)
If `npx shadcn@latest add` fails with npm cache errors like `ENOTEMPTY` or `syscall rename`:
**Solution 1: Clear npm cache**
```bash
npm cache clean --force
npx shadcn@latest add table
```
**Solution 2: Use pnpm (recommended)**
```bash
pnpm dlx shadcn@latest add table
```
**Solution 3: Use yarn**
```bash
yarn dlx shadcn@latest add table
```
**Solution 4: Manual component installation**
Visit the [shadcn/ui documentation](https://ui.shadcn.com/docs/components) for the specific component and copy the code directly into your project.
## Component Usage
### Button & Card
```typescript
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';
// Variants
// Card
{post.title}
{post.author}
{post.excerpt}
```
### Dialog
```typescript
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
export function CreatePostDialog() {
return (
);
}
```
## Forms
### Basic Form with react-hook-form
```typescript
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as 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';
import { Textarea } from '@/components/ui/textarea';
const formSchema = z.object({
title: z.string().min(1, 'Title is required'),
content: z.string().min(10, 'Content must be at least 10 characters')
});
export function PostForm() {
const form = useForm>({
resolver: zodResolver(formSchema),
defaultValues: {
title: '',
content: ''
}
});
const onSubmit = (values: z.infer) => {
console.log(values);
};
return (
);
}
```
### Select Field
```typescript
(
Category
)}
/>
```
## Data Display
### Table
```typescript
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
export function PostsTable({ posts }: { posts: Post[] }) {
return (
Title
Author
Status
Actions
{posts.map((post) => (
{post.title}
{post.author.name}
{post.published ? 'Published' : 'Draft'}
))}
);
}
```
## Navigation
### Badge & Dropdown Menu
```typescript
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { Button } from '@/components/ui/button';
export function UserMenu() {
return (
My Account
Profile
Settings
Log out
);
}
```
### Tabs
```typescript
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
export function PostTabs() {
return (
Published
Drafts
Archived
);
}
```
## Feedback
### Toast
```typescript
'use client';
import { useToast } from '@/components/ui/use-toast';
import { Button } from '@/components/ui/button';
export function ToastExample() {
const { toast } = useToast();
return (
);
}
// With variant
toast({
variant: 'destructive',
title: 'Error',
description: 'Failed to create post. Please try again.'
});
```
### Alert
```typescript
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { AlertCircle } from 'lucide-react';
export function AlertExample() {
return (
Error
Your session has expired. Please log in again.
);
}
```
## Loading States
### Skeleton
```typescript
import { Skeleton } from '@/components/ui/skeleton';
export function PostCardSkeleton() {
return (
);
}
```
## Customization
### Modifying Components
Components are in your codebase - edit them directly:
```typescript
// components/ui/button.tsx
export const buttonVariants = cva(
"inline-flex items-center justify-center...",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
// Add custom variant
brand: "bg-gradient-to-r from-blue-500 to-purple-600 text-white"
}
}
}
);
```
### Using Custom Variant
```typescript
```
## Theming
### CSS Variables (OKLCH Format)
shadcn/ui now uses OKLCH color format for better color accuracy and perceptual uniformity:
```css
/* app/globals.css */
@layer base {
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
/* ... */
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.598 0.15 264);
--primary-foreground: oklch(0.205 0 0);
/* ... */
}
}
```
### Dark Mode
```typescript
// components/theme-toggle.tsx
'use client';
import { Moon, Sun } from 'lucide-react';
import { useTheme } from 'next-themes';
import { Button } from '@/components/ui/button';
export function ThemeToggle() {
const { setTheme, theme } = useTheme();
return (
);
}
```
## Composition Patterns
### Combining Components
```typescript
export function CreatePostCard() {
return (
Create Post
Share your thoughts with the world
);
}
```
### Modal with Form
```typescript
export function CreatePostModal() {
const [open, setOpen] = useState(false);
return (
);
}
```
## Additional Resources
For detailed information, see:
- [Component Catalog](resources/component-catalog.md)
- [Form Patterns](resources/form-patterns.md)
- [Theming Guide](resources/theming.md)