--- name: shadcn description: This skill should be used when the user asks to "add a component", "use shadcn", "install Button", "create Dialog", "add Form", "use DataTable", "implement dark mode toggle", "use cn utility", or discusses UI components, component libraries, or accessible components. Always use the latest shadcn/ui version and modern patterns. version: 1.0.0 --- # shadcn/ui Development This skill provides guidance for building interfaces with shadcn/ui, focusing on **always using the latest version** and modern patterns. > **Philosophy:** Copy and own your components. Use the `new-york` style. Leverage Radix UI primitives for accessibility. ## Quick Reference | Feature | Modern Approach | Legacy (Avoid) | |---------|----------------|----------------| | Style | `new-york` | `default` (deprecated) | | Toast | `sonner` | `toast` component | | Animation | CSS/tw-animate-css | `tailwindcss-animate` | | forwardRef | Direct `ref` prop (React 19) | `forwardRef` wrapper | ## Installation ### Initialize in Next.js ```bash npx shadcn@latest init ``` Configuration prompts: - Style: **new-york** (recommended) - Base color: neutral, slate, zinc, gray, or stone - CSS variables: **Yes** (recommended) ### Add Components ```bash # Add individual components npx shadcn@latest add button npx shadcn@latest add card dialog form input # Add multiple components npx shadcn@latest add button card dialog form input label textarea ``` ## The cn() Utility Merge Tailwind classes conditionally: ```tsx import { cn } from "@/lib/utils" interface ButtonProps extends React.ButtonHTMLAttributes { variant?: 'default' | 'destructive' | 'outline' size?: 'sm' | 'md' | 'lg' } export function Button({ className, variant = 'default', size = 'md', ...props }: ButtonProps) { return ( // Sizes // States ``` ### Card ```tsx import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card" Card Title Card description goes here

Card content

``` ### Dialog ```tsx import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DialogClose, } from "@/components/ui/dialog" Are you sure? This action cannot be undone.
Dialog body content
``` ### Input & Label ```tsx import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label"
``` ### Select ```tsx import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" ``` ## Form Handling ### With React Hook Form + Zod ```tsx '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" const formSchema = z.object({ username: z.string().min(2, "Username must be at least 2 characters"), email: z.string().email("Invalid email address"), }) type FormValues = z.infer export function ProfileForm() { const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { username: "", email: "", }, }) function onSubmit(values: FormValues) { console.log(values) } return (
( Username Your public display name. )} /> ( Email )} /> ) } ``` ### With Server Actions ```tsx 'use client' import { useActionState } from 'react' import { createUser } from './actions' import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" export function SignupForm() { const [state, formAction, isPending] = useActionState(createUser, { error: null }) return (
{state.error && (

{state.error}

)}
) } ``` ## Dark Mode ### Theme Provider Setup ```tsx // components/theme-provider.tsx 'use client' import * as React from 'react' import { ThemeProvider as NextThemesProvider } from 'next-themes' export function ThemeProvider({ children, ...props }: React.ComponentProps) { return {children} } ``` ```tsx // app/layout.tsx import { ThemeProvider } from "@/components/theme-provider" export default function RootLayout({ children }) { return ( {children} ) } ``` ### Theme Toggle ```tsx 'use client' import { useTheme } from 'next-themes' import { Button } from "@/components/ui/button" import { Moon, Sun } from "lucide-react" export function ThemeToggle() { const { theme, setTheme } = useTheme() return ( ) } ``` ## Toast Notifications (Sonner) ```tsx // app/layout.tsx import { Toaster } from "@/components/ui/sonner" export default function RootLayout({ children }) { return ( {children} ) } ``` ```tsx // In components import { toast } from "sonner" function MyComponent() { return ( ) } // Other toast types toast("Default toast") toast.success("Success message") toast.error("Error message") toast.warning("Warning message") toast.info("Info message") toast.loading("Loading...") // With action toast("Event created", { action: { label: "Undo", onClick: () => console.log("Undo") } }) // Promise-based toast.promise(saveData(), { loading: "Saving...", success: "Saved!", error: "Error saving" }) ``` ## Common Patterns ### Responsive Sheet/Dialog ```tsx 'use client' import { useMediaQuery } from "@/hooks/use-media-query" import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog" import { Sheet, SheetContent, SheetHeader, SheetTitle, } from "@/components/ui/sheet" interface ResponsiveModalProps { open: boolean onOpenChange: (open: boolean) => void title: string children: React.ReactNode } export function ResponsiveModal({ open, onOpenChange, title, children }: ResponsiveModalProps) { const isDesktop = useMediaQuery("(min-width: 768px)") if (isDesktop) { return ( {title} {children} ) } return ( {title} {children} ) } ``` ### Loading Button ```tsx import { Loader2 } from "lucide-react" import { Button } from "@/components/ui/button" interface LoadingButtonProps extends React.ComponentProps { loading?: boolean } export function LoadingButton({ children, loading, disabled, ...props }: LoadingButtonProps) { return ( ) } ``` ## Additional Resources For detailed patterns, see reference files: - **`references/components.md`** - Full component catalog - **`references/theming.md`** - Theme customization