Skip to main content Home Creators blencorp claude-code-kit shadcn
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.
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/blencorp/claude-code-kit --skill shadcnThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository 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.
skill-rules-fragment.json 774 B Related occupations SOC
Based on SOC occupation classification
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
Copy, Don't Install : Components are copied to your project, not installed as dependencies
Customizable : Modify components directly in your codebase
Accessible : Built on Radix UI primitives with ARIA support
Type-Safe : Full TypeScript support
Composable : Build complex UIs from simple primitives
Installation
Initial Setup
npx shadcn@latest init
Add Components
npx shadcn@latest add button
npx shadcn@latest add form
npx shadcn@latest add dialog
npx shadcn@latest add button card dialog
Troubleshooting
npm Cache Errors (ENOTEMPTY)
If npx shadcn@latest add fails with npm cache errors like or :
ENOTEMPTY
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
yarn dlx shadcn@latest add table
Solution 4: Manual component installation
Component Usage
Button & Card import { Button } from '@/components/ui/button' ;
import { Card , CardHeader , CardTitle , CardDescription , CardContent } from '@/components/ui/card' ;
<Button > Default</Button >
<Button variant ="destructive" > Destructive</Button >
<Button variant ="outline" > Outline</Button >
<Card >
<CardHeader >
<CardTitle > {post.title}</CardTitle >
<CardDescription > {post.author}</CardDescription >
</CardHeader >
<CardContent >
<p > {post.excerpt}</p >
</CardContent >
</Card >
Dialog 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 >
);
}
Forms
Basic Form with react-hook-form '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 = { } />
)}
/>
Create Post
);
}
Select Field <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 >
)}
/>
Data Display
Table 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 >
);
}
Navigation
Badge & Dropdown Menu 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 >
);
}
Tabs 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 >
);
}
Feedback
Toast '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 >
);
}
toast ({
variant : 'destructive' ,
title : 'Error' ,
description : 'Failed to create post. Please try again.'
});
Alert 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 >
);
}
Loading States
Skeleton 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 >
);
}
Customization
Modifying Components Components are in your codebase - edit them directly:
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" ,
brand : "bg-gradient-to-r from-blue-500 to-purple-600 text-white"
}
}
}
);
Using Custom Variant <Button variant="brand" >Custom Brand Button </Button >
Theming
CSS Variables (OKLCH Format) shadcn/ui now uses OKLCH color format for better color accuracy and perceptual uniformity:
@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
'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 >
);
}
Composition Patterns
Combining Components 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 >
);
}
Modal with Form 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 >
);
}
Additional Resources For detailed information, see:
"Write your post..."
...field
</FormControl >
<FormMessage />
</FormItem >
<Button type ="submit" >
</Button >
</form >
</Form >