Claude-skill-registry frontend-shadcn
DEFAULT foundation component library for all React/Next.js UI needs. Use as the starting point for any project needing buttons, inputs, dialogs, forms, tables, navigation, modals, dropdowns, and other standard UI elements. Built on Radix UI + Tailwind CSS. Check shadcn FIRST before reaching for other libraries.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/frontend-shadcn" ~/.claude/skills/majiayu000-claude-skill-registry-frontend-shadcn && rm -rf "$T"
manifest:
skills/data/frontend-shadcn/SKILL.mdsource content
shadcn/ui Component Library
Overview
shadcn/ui is NOT a component library you install via npm. It's a collection of re-usable components that you copy and paste into your project. You OWN the code.
Philosophy: Copy-paste → Own the code → Customize freely
Built on: Radix UI (accessibility) + Tailwind CSS (styling) + CVA (variants)
When to Use This Skill
- Starting ANY new React/Next.js project
- Need standard UI components (buttons, inputs, dialogs, etc.)
- Building forms, tables, navigation
- Need accessible, production-ready components
- User asks for "basic UI", "form", "modal", "dropdown", etc.
This is your DEFAULT starting point. Always check shadcn/ui first.
Quick Start
Project Setup
# Initialize shadcn/ui in your project npx shadcn@latest init # Answer prompts: # - Style: Default or New York # - Base color: Slate, Gray, Zinc, Neutral, Stone # - CSS variables: Yes (recommended)
Add Components
# Add single component npx shadcn@latest add button # Add multiple components npx shadcn@latest add button card dialog # Add ALL components npx shadcn@latest add --all
Complete Component Reference
Forms & Inputs
| Component | Command | Use Case |
|---|---|---|
| Button | | Primary actions, CTAs |
| Input | | Text fields |
| Textarea | | Multi-line text |
| Select | | Dropdown selection |
| Native Select | | Native HTML select |
| Checkbox | | Boolean options |
| Radio Group | | Single choice from options |
| Switch | | Toggle on/off |
| Slider | | Range selection |
| Input OTP | | One-time password input |
| Form | | Form with react-hook-form + zod |
| Label | | Form field labels |
| Field | | Form field wrapper |
// Button variants <Button>Default</Button> <Button variant="secondary">Secondary</Button> <Button variant="destructive">Delete</Button> <Button variant="outline">Outline</Button> <Button variant="ghost">Ghost</Button> <Button variant="link">Link</Button> <Button size="sm">Small</Button> <Button size="lg">Large</Button> <Button size="icon"><Icon /></Button>
// Form example with validation import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import * as z from "zod" const schema = z.object({ email: z.string().email(), password: z.string().min(8), }) export function LoginForm() { const form = useForm({ resolver: zodResolver(schema), }) return ( <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>Email</FormLabel> <FormControl> <Input {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <Button type="submit">Login</Button> </form> </Form> ) }
Overlays & Modals
| Component | Command | Use Case |
|---|---|---|
| Dialog | | Modal windows, confirmations |
| Alert Dialog | | Destructive action confirmations |
| Sheet | | Side panels (mobile nav, filters) |
| Drawer | | Bottom sheets (mobile) |
| Popover | | Floating content, pickers |
| Tooltip | | Hover hints |
| Hover Card | | Rich hover previews |
| Context Menu | | Right-click menus |
| Dropdown Menu | | Action menus |
// Dialog example <Dialog> <DialogTrigger asChild> <Button>Open</Button> </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Edit Profile</DialogTitle> <DialogDescription> Make changes to your profile here. </DialogDescription> </DialogHeader> {/* content */} <DialogFooter> <Button type="submit">Save</Button> </DialogFooter> </DialogContent> </Dialog>
// Sheet (side panel) <Sheet> <SheetTrigger asChild> <Button variant="outline">Open Menu</Button> </SheetTrigger> <SheetContent side="left"> {/* left | right | top | bottom */} <SheetHeader> <SheetTitle>Menu</SheetTitle> </SheetHeader> {/* navigation links */} </SheetContent> </Sheet>
Navigation
| Component | Command | Use Case |
|---|---|---|
| Navigation Menu | | Main site navigation |
| Menubar | | App menubar (File, Edit, View) |
| Breadcrumb | | Page hierarchy |
| Pagination | | Page navigation |
| Tabs | | Content sections |
| Command | | Command palette (⌘K) |
| Sidebar | | App sidebar navigation |
// Tabs example <Tabs defaultValue="account"> <TabsList> <TabsTrigger value="account">Account</TabsTrigger> <TabsTrigger value="password">Password</TabsTrigger> </TabsList> <TabsContent value="account">Account settings...</TabsContent> <TabsContent value="password">Password settings...</TabsContent> </Tabs>
// Command palette (cmdk) <Command> <CommandInput placeholder="Type a command..." /> <CommandList> <CommandEmpty>No results found.</CommandEmpty> <CommandGroup heading="Suggestions"> <CommandItem>Calendar</CommandItem> <CommandItem>Search</CommandItem> <CommandItem>Settings</CommandItem> </CommandGroup> </CommandList> </Command>
Layout & Structure
| Component | Command | Use Case |
|---|---|---|
| Card | | Content containers |
| Accordion | | Collapsible sections |
| Collapsible | | Toggle content visibility |
| Separator | | Visual dividers |
| Aspect Ratio | | Fixed aspect containers |
| Scroll Area | | Custom scrollbars |
| Resizable | | Resizable panels |
// Card example <Card> <CardHeader> <CardTitle>Card Title</CardTitle> <CardDescription>Card description</CardDescription> </CardHeader> <CardContent> <p>Card content here</p> </CardContent> <CardFooter> <Button>Action</Button> </CardFooter> </Card>
// Accordion <Accordion type="single" collapsible> <AccordionItem value="item-1"> <AccordionTrigger>Is it accessible?</AccordionTrigger> <AccordionContent> Yes. It follows WAI-ARIA patterns. </AccordionContent> </AccordionItem> </Accordion>
Data Display
| Component | Command | Use Case |
|---|---|---|
| Table | | Basic tables |
| Data Table | | Advanced tables (sorting, filtering) |
| Avatar | | User images |
| Badge | | Status labels, tags |
| Calendar | | Date picker calendar |
| Date Picker | | Date selection |
| Carousel | | Image/content sliders |
| Chart | | Data visualization (Recharts) |
// Table <Table> <TableHeader> <TableRow> <TableHead>Name</TableHead> <TableHead>Email</TableHead> <TableHead>Status</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>John Doe</TableCell> <TableCell>john@example.com</TableCell> <TableCell><Badge>Active</Badge></TableCell> </TableRow> </TableBody> </Table>
// Badge variants <Badge>Default</Badge> <Badge variant="secondary">Secondary</Badge> <Badge variant="destructive">Error</Badge> <Badge variant="outline">Outline</Badge>
Feedback
| Component | Command | Use Case |
|---|---|---|
| Alert | | Inline messages |
| Toast | | Brief notifications |
| Sonner | | Better toast notifications |
| Progress | | Loading progress |
| Skeleton | | Loading placeholders |
| Spinner | | Loading indicator |
| Empty | | Empty state placeholder |
// Alert <Alert> <AlertTitle>Heads up!</AlertTitle> <AlertDescription> You can add components to your app. </AlertDescription> </Alert> <Alert variant="destructive"> <AlertTitle>Error</AlertTitle> <AlertDescription>Something went wrong.</AlertDescription> </Alert>
// Toast (using Sonner - recommended) import { toast } from "sonner" // Trigger toast toast.success("Profile updated!") toast.error("Something went wrong") toast.loading("Saving...")
// Skeleton loading <div className="space-y-2"> <Skeleton className="h-4 w-[250px]" /> <Skeleton className="h-4 w-[200px]" /> </div>
Utility
| Component | Command | Use Case |
|---|---|---|
| Toggle | | On/off button |
| Toggle Group | | Multiple toggles |
| Combobox | | Searchable select |
| Typography | | Text styles |
| Kbd | | Keyboard shortcut hints |
| Button Group | | Grouped buttons |
| Input Group | | Input with addons |
| Item | | List item component |
// Combobox (searchable select) <Popover open={open} onOpenChange={setOpen}> <PopoverTrigger asChild> <Button variant="outline" role="combobox"> {value || "Select framework..."} </Button> </PopoverTrigger> <PopoverContent> <Command> <CommandInput placeholder="Search..." /> <CommandList> <CommandEmpty>No results.</CommandEmpty> <CommandGroup> {frameworks.map((framework) => ( <CommandItem key={framework.value} onSelect={() => setValue(framework.value)} > {framework.label} </CommandItem> ))} </CommandGroup> </CommandList> </Command> </PopoverContent> </Popover>
Common Patterns
Loading Button
import { Loader2 } from "lucide-react" <Button disabled={isLoading}> {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} {isLoading ? "Loading..." : "Submit"} </Button>
Confirmation Dialog
<AlertDialog> <AlertDialogTrigger asChild> <Button variant="destructive">Delete</Button> </AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Are you sure?</AlertDialogTitle> <AlertDialogDescription> This action cannot be undone. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction onClick={handleDelete}> Delete </AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog>
Search with Command
<Dialog> <DialogTrigger asChild> <Button variant="outline" className="w-[200px] justify-start"> <Search className="mr-2 h-4 w-4" /> Search... <Kbd className="ml-auto">⌘K</Kbd> </Button> </DialogTrigger> <DialogContent className="p-0"> <Command> <CommandInput placeholder="Search..." /> <CommandList> <CommandEmpty>No results.</CommandEmpty> <CommandGroup heading="Pages"> <CommandItem>Dashboard</CommandItem> <CommandItem>Settings</CommandItem> </CommandGroup> </CommandList> </Command> </DialogContent> </Dialog>
Responsive Mobile Menu
// Desktop: Navigation Menu // Mobile: Sheet with menu <div className="hidden md:block"> <NavigationMenu>{/* desktop nav */}</NavigationMenu> </div> <div className="md:hidden"> <Sheet> <SheetTrigger asChild> <Button variant="ghost" size="icon"> <Menu /> </Button> </SheetTrigger> <SheetContent side="left"> {/* mobile nav links */} </SheetContent> </Sheet> </div>
Theming
CSS Variables (globals.css)
@layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.5rem; } .dark { --background: 240 10% 3.9%; --foreground: 0 0% 98%; /* ... dark mode values */ } }
Using Theme Colors
// In Tailwind classes <div className="bg-background text-foreground" /> <div className="bg-primary text-primary-foreground" /> <div className="bg-muted text-muted-foreground" /> <div className="border-border" />
Component Customization
Extending Variants (CVA)
// components/ui/button.tsx import { cva } from "class-variance-authority" const buttonVariants = cva( "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground", outline: "border border-input bg-background hover:bg-accent", secondary: "bg-secondary text-secondary-foreground", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", // Add custom variants success: "bg-green-600 text-white hover:bg-green-700", warning: "bg-yellow-500 text-black hover:bg-yellow-600", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", // Add custom sizes xl: "h-14 rounded-lg px-10 text-lg", }, }, defaultVariants: { variant: "default", size: "default", }, } )
Decision Guide
Need a component? │ ▼ ┌──────────────────────────┐ │ Is it a STANDARD UI │ │ element? (button, input, │ │ modal, table, form...) │ └──────────────────────────┘ │ YES ─┴─ NO │ │ ▼ ▼ shadcn Check Aceternity /ui or Magic UI
Troubleshooting
"Component not found": → npx shadcn@latest add [component] --overwrite → Check components.json exists "Styles not applying": → Check tailwind.config.ts content paths → Check globals.css has CSS variables "Hydration mismatch (Dialog/Sheet)": → Add suppressHydrationWarning to <html> → Use dynamic(() => import(...), { ssr: false }) "Dark mode not working": → npm install next-themes → Add darkMode: ['class'] to tailwind.config.ts → Wrap app with ThemeProvider "Form errors not showing": → Include <FormMessage /> in FormField → Check zodResolver(schema) is set
References
- patterns.md — Dark mode toggle, multi-step forms, data tables, file upload
External Resources
- https://ui.shadcn.com/docs — Documentation
- https://ui.shadcn.com/docs/components — Components list
- https://ui.shadcn.com/themes — Theme generator
- https://ui.shadcn.com/blocks — Example blocks