一键导入
shadcn
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.
菜单
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.
Express.js framework patterns including routing, middleware, request/response handling, and Express-specific APIs. Use when working with Express routes, middleware, or Express applications.
Material-UI v7 component library patterns including sx prop styling, theme integration, responsive design, and MUI-specific hooks. Use when working with MUI components, styling with sx prop, theme customization, or MUI utilities.
Next.js 15+ App Router development patterns including Server Components, Client Components, data fetching, layouts, and server actions. Use when creating pages, routes, layouts, components, API route handlers, server actions, loading states, error boundaries, or working with Next.js navigation and metadata.
Core Node.js backend patterns for TypeScript applications including async/await error handling, middleware concepts, configuration management, testing strategies, and layered architecture principles. Use when building Node.js backend services, APIs, or microservices.
Prisma ORM patterns including Prisma Client usage, queries, mutations, relations, transactions, and schema management. Use when working with Prisma database operations or schema definitions.
Core React 19 patterns including hooks, Suspense, lazy loading, component structure, TypeScript best practices, and performance optimization. Use when working with React components, hooks, lazy loading, Suspense boundaries, or React-specific TypeScript patterns.
| 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 |
Best practices for using shadcn/ui components with Tailwind CSS and Radix UI primitives.
npx shadcn@latest init
# 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
If npx shadcn@latest add fails with npm cache errors like ENOTEMPTY or syscall rename:
Solution 1: Clear npm cache
npm cache clean --force
npx shadcn@latest add table
Solution 2: Use pnpm (recommended)
pnpm dlx shadcn@latest add table
Solution 3: Use yarn
yarn dlx shadcn@latest add table
Solution 4: Manual component installation
Visit the shadcn/ui documentation for the specific component and copy the code directly into your project.
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card';
// Variants
<Button>Default</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
// Card
<Card>
<CardHeader>
<CardTitle>{post.title}</CardTitle>
<CardDescription>{post.author}</CardDescription>
</CardHeader>
<CardContent>
<p>{post.excerpt}</p>
</CardContent>
</Card>
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
export function CreatePostDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Create Post</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create New Post</DialogTitle>
<DialogDescription>
Fill in the details below to create a new post.
</DialogDescription>
</DialogHeader>
<PostForm />
</DialogContent>
</Dialog>
);
}
'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<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
title: '',
content: ''
}
});
const onSubmit = (values: z.infer<typeof formSchema>) => {
console.log(values);
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input placeholder="Post title" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="content"
render={({ field }) => (
<FormItem>
<FormLabel>Content</FormLabel>
<FormControl>
<Textarea placeholder="Write your post..." {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Create Post</Button>
</form>
</Form>
);
}
<FormField
control={form.control}
name="category"
render={({ field }) => (
<FormItem>
<FormLabel>Category</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select a category" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="tech">Technology</SelectItem>
<SelectItem value="design">Design</SelectItem>
<SelectItem value="business">Business</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
export function PostsTable({ posts }: { posts: Post[] }) {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Title</TableHead>
<TableHead>Author</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{posts.map((post) => (
<TableRow key={post.id}>
<TableCell className="font-medium">{post.title}</TableCell>
<TableCell>{post.author.name}</TableCell>
<TableCell>
<Badge variant={post.published ? 'default' : 'secondary'}>
{post.published ? 'Published' : 'Draft'}
</Badge>
</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm">Edit</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { Button } from '@/components/ui/button';
export function UserMenu() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost">
<User className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
export function PostTabs() {
return (
<Tabs defaultValue="published">
<TabsList>
<TabsTrigger value="published">Published</TabsTrigger>
<TabsTrigger value="drafts">Drafts</TabsTrigger>
<TabsTrigger value="archived">Archived</TabsTrigger>
</TabsList>
<TabsContent value="published">
<PublishedPosts />
</TabsContent>
<TabsContent value="drafts">
<DraftPosts />
</TabsContent>
<TabsContent value="archived">
<ArchivedPosts />
</TabsContent>
</Tabs>
);
}
'use client';
import { useToast } from '@/components/ui/use-toast';
import { Button } from '@/components/ui/button';
export function ToastExample() {
const { toast } = useToast();
return (
<Button
onClick={() => {
toast({
title: 'Post created',
description: 'Your post has been published successfully.'
});
}}
>
Create Post
</Button>
);
}
// With variant
toast({
variant: 'destructive',
title: 'Error',
description: 'Failed to create post. Please try again.'
});
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { AlertCircle } from 'lucide-react';
export function AlertExample() {
return (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Your session has expired. Please log in again.
</AlertDescription>
</Alert>
);
}
import { Skeleton } from '@/components/ui/skeleton';
export function PostCardSkeleton() {
return (
<div className="flex flex-col space-y-3">
<Skeleton className="h-[125px] w-full rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
);
}
Components are in your codebase - edit them directly:
// 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"
}
}
}
);
<Button variant="brand">Custom Brand Button</Button>
shadcn/ui now uses OKLCH color format for better color accuracy and perceptual uniformity:
/* 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);
/* ... */
}
}
// 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 (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
>
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}
export function CreatePostCard() {
return (
<Card>
<CardHeader>
<CardTitle>Create Post</CardTitle>
<CardDescription>Share your thoughts with the world</CardDescription>
</CardHeader>
<CardContent>
<PostForm />
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline">Save Draft</Button>
<Button>Publish</Button>
</CardFooter>
</Card>
);
}
export function CreatePostModal() {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>New Post</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[600px]">
<DialogHeader>
<DialogTitle>Create Post</DialogTitle>
</DialogHeader>
<PostForm onSuccess={() => setOpen(false)} />
</DialogContent>
</Dialog>
);
}
For detailed information, see: