shadcn-ui
npx skills add https://smithery.ai
Agent 安装分布
Skill 文档
Shadcn-UI Skill
Expert assistance with shadcn/ui – a collection of beautifully-designed, accessible components built with TypeScript, Tailwind CSS, and Radix UI primitives. Supports Next.js, Vite, Remix, Astro, Laravel, and more.
When to Use This Skill
This skill should be triggered when:
- Installing or configuring shadcn/ui in any supported framework
- Adding shadcn/ui components (Button, Dialog, Form, Table, etc.)
- Implementing forms with React Hook Form or TanStack Form
- Setting up dark mode with shadcn/ui theming
- Customizing component styles or design tokens
- Building data tables with sorting/filtering/pagination
- Working with overlays (dialogs, sheets, popovers, tooltips)
- Creating accessible navigation components
- Implementing toast notifications or alerts
- Using the shadcn CLI to add components
- Customizing components.json configuration
- Building charts or carousels with shadcn/ui
- Questions about shadcn/ui best practices or patterns
Quick Reference
Installation and CLI
# Initialize shadcn/ui in a project
npx shadcn@latest init
# Add specific components
npx shadcn@latest add button
npx shadcn@latest add dialog form input
# Add all components
npx shadcn@latest add
Basic Button Component
import { Button } from "@/components/ui/button"
export default function Example() {
return (
<div className="flex gap-2">
<Button>Default</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Cancel</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
</div>
)
}
Form with Validation
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import { Button } from "@/components/ui/button"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
const formSchema = z.object({
username: z.string().min(2).max(50),
email: z.string().email(),
})
export default function ProfileForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
})
function 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="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="johndoe" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
)
}
Dialog Component
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
export default function Example() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This action cannot be undone.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
)
}
Toast Notifications
import { useToast } from "@/hooks/use-toast"
import { Button } from "@/components/ui/button"
export default function Example() {
const { toast } = useToast()
return (
<Button
onClick={() => {
toast({
title: "Success",
description: "Your changes have been saved.",
})
}}
>
Show Toast
</Button>
)
}
Data Table with Sorting
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
const invoices = [
{ id: "INV001", status: "Paid", amount: "$250.00" },
{ id: "INV002", status: "Pending", amount: "$150.00" },
]
export default function DataTable() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.id}>
<TableCell>{invoice.id}</TableCell>
<TableCell>{invoice.status}</TableCell>
<TableCell>{invoice.amount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)
}
Select Dropdown
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
export default function Example() {
return (
<Select>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="banana">Banana</SelectItem>
<SelectItem value="orange">Orange</SelectItem>
</SelectContent>
</Select>
)
}
Dark Mode Setup (Next.js)
// app/providers.tsx
"use client"
import { ThemeProvider } from "next-themes"
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
)
}
// Usage in component
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
export function ThemeToggle() {
const { setTheme } = useTheme()
return (
<Button onClick={() => setTheme("dark")}>Dark Mode</Button>
)
}
Card Component
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
export default function Example() {
return (
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content</p>
</CardContent>
</Card>
)
}
Combobox (Searchable Select)
import { Check, ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
const frameworks = [
{ value: "next", label: "Next.js" },
{ value: "react", label: "React" },
{ value: "vue", label: "Vue" },
]
export default function Combobox() {
const [open, setOpen] = React.useState(false)
const [value, setValue] = React.useState("")
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline" className="w-[200px] justify-between">
{value || "Select framework..."}
<ChevronsUpDown className="ml-2 h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search..." />
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
onSelect={() => {
setValue(framework.value)
setOpen(false)
}}
>
<Check className={value === framework.value ? "mr-2 h-4 w-4" : "mr-2 h-4 w-4 opacity-0"} />
{framework.label}
</CommandItem>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
)
}
Reference Files
This skill includes comprehensive documentation in references/:
llms.md
Complete overview of shadcn/ui with links to all components and features. Covers:
- Core principles (Open Code, Composition, Distribution, Beautiful Defaults, AI-Ready)
- Installation guides for all supported frameworks (Next.js, Vite, Remix, Astro, Laravel, etc.)
- Complete component catalog organized by category
- Dark mode setup for different frameworks
- Forms integration (React Hook Form, TanStack Form)
- Advanced topics (monorepo, React 19, Tailwind v4, JavaScript usage)
- Registry system for publishing/distributing components
- MCP Server integration for AI assistants
other.md
Additional documentation mirroring llms.md content with organized sections for:
- All component categories (Form & Input, Layout & Navigation, Overlays & Dialogs, etc.)
- Installation instructions by framework
- Dark mode configuration
- Registry schemas
Use view references/llms.md for quick access to component links and documentation structure.
Working with This Skill
For Beginners
- Start by initializing shadcn/ui:
npx shadcn@latest init - Add basic components like Button, Input, and Card to learn the patterns
- Review the Quick Reference examples above for common use cases
- Use
references/llms.mdto explore available components by category
For Building Forms
- Install form components:
npx shadcn@latest add form input - Set up React Hook Form with Zod validation (see Form example above)
- Use Field component for labels and error messages
- Check the Forms section in references for advanced patterns
For Complex Components
- Check component categories in references (Data Table, Command, Combobox)
- Install required dependencies (some components use external libraries)
- Follow the component-specific documentation links
- Customize using Tailwind classes and component props
For Theming
- Edit
components.jsonto configure paths and styling - Use the Theming guide for customizing colors and design tokens
- Set up dark mode using the framework-specific guide
- Override CSS variables for fine-grained control
Key Concepts
Component Philosophy
- Open Code: Components are copied into your project, not installed as dependencies
- Composition: Components are built using Radix UI primitives for accessibility
- Customization: Full control over styling using Tailwind CSS
- Copy-paste friendly: Modify components directly in your codebase
Installation Model
Unlike traditional libraries, shadcn/ui components are added to your project via CLI:
- Components live in your
components/uidirectory - You have full ownership and can modify them
- No package.json dependency (except for Radix UI and utilities)
- Update components by re-running
addcommand
components.json
Central configuration file that controls:
- Component installation paths
- TypeScript/JavaScript preference
- Tailwind CSS configuration
- Style variants (default/new-york)
- CSS variable usage
- Import aliases
Styling Approach
- Uses Tailwind CSS utility classes
- CSS variables for theming (light/dark mode)
cn()utility for conditional classes- Variants defined using
class-variance-authority
Accessibility
All components built on Radix UI primitives ensure:
- Keyboard navigation
- Screen reader support
- ARIA attributes
- Focus management
Framework Support
Works with any React framework through appropriate setup:
- Next.js: App Router and Pages Router
- Vite: Standard React setup
- Remix: Requires specific configuration
- Astro: React integration
- Laravel: Via Inertia.js
- Others: Manual installation guide available
Common Patterns
Async Form Submission (Next.js Server Actions)
"use server"
async function onSubmit(formData: FormData) {
const data = {
name: formData.get("name"),
email: formData.get("email"),
}
// Process data
return { success: true }
}
Responsive Dialog/Sheet
Use Dialog for desktop, Sheet for mobile:
import { useMediaQuery } from "@/hooks/use-media-query"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Sheet, SheetContent } from "@/components/ui/sheet"
const isDesktop = useMediaQuery("(min-width: 768px)")
if (isDesktop) {
return <Dialog>...</Dialog>
}
return <Sheet>...</Sheet>
Controlled Components
const [open, setOpen] = useState(false)
const [value, setValue] = useState("")
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>...</DialogContent>
</Dialog>
Resources
Official Documentation
- Main site: https://ui.shadcn.com
- Components: https://ui.shadcn.com/docs/components
- CLI: https://ui.shadcn.com/docs/cli
- Themes: https://ui.shadcn.com/themes
Tools
- v0 by Vercel: AI-powered UI generation with shadcn/ui
- Figma: Design resources available
- MCP Server: AI assistant integration for Claude Code, Cursor, etc.
Registry
Create and publish your own component collections:
- Set up private or public registries
- Share components across projects
- Use authentication for private registries
Troubleshooting
Import Errors
Ensure your tsconfig.json has the correct path aliases:
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
Styling Issues
- Verify Tailwind CSS is configured with
tailwind.config.js - Check that globals.css imports are present
- Ensure
cn()utility is inlib/utils.ts
Component Not Found
Run npx shadcn@latest add <component-name> to install missing components
Notes
- Components are framework-agnostic and work with any React setup
- Dark mode requires theme provider (next-themes or similar)
- Some components depend on external libraries (date-fns, recharts, etc.)
- The CLI handles dependency installation automatically
- Components can be customized without breaking updates
- Registry system allows publishing custom component collections
- MCP integration enables AI-powered component installation