shadcn
shadcn/ui — Radix UI + Tailwind copy-paste; MCP for component install.
Files1
View on GitHubSKILL.mdskills/ui-libraries/shadcn/SKILL.md
GitHubDetection Signals
components/ui/directory with component files (button.tsx,card.tsx,dialog.tsx)components.jsonat project root@radix-ui/*andlucide-reactinpackage.jsoncn()utility import from@/lib/utilsclass-variance-authority(cva) in dependencies
MCP Setup
shadcn/ui has an official MCP that enables component browsing, searching, and installation via natural language.
Add to .claude/settings.json (or .claude/settings.local.json for local-only):
{
"mcpServers": {
"shadcn-ui": {
"command": "npx",
"args": ["-y", "shadcn@latest", "mcp"]
}
}
}
If auto-configuration fails, ask the user to add the entry manually in their CLI's MCP settings (Claude Code → Settings → MCP Servers; the
mcpblock ofopencode.json; Codex CLI's MCP config). Once active, components can be requested by description and the MCP handles installation.
Core Concepts
| Concept | Detail |
|---|---|
| Copy-paste | Components live in components/ui/ — owned by the project, not a package |
| Radix UI | Accessible, unstyled headless primitives under the hood |
| Tailwind CSS | All styling via utility classes |
cn() utility |
clsx + tailwind-merge — required for safe class merging |
| CVA | class-variance-authority — defines component variants |
| CLI | npx shadcn@latest add <component> installs with all dependencies |
Component Patterns
// Always use cn() for className merging — never string concatenation
import { cn } from "@/lib/utils"
<Button className={cn("w-full", isLoading && "opacity-50")} />
// Variants via CVA — check the component file for available variant values
<Button variant="destructive" size="sm" />
// asChild for polymorphism — render as a different element without wrapper hacks
<Button asChild>
<Link href="/dashboard">Go to dashboard</Link>
</Button>
CLI Reference
npx shadcn@latest add button # add single component
npx shadcn@latest add dialog sheet # add multiple at once
npx shadcn@latest diff # check for component updates
Critical Rules
- Never install as a package — components are meant to be copied into the project; importing from node_modules defeats the model
- Always use
cn()for merging classNames — direct concatenation causes Tailwind class conflicts - Customize in
components/ui/— that is the intended extension point; no need to wrap or fork - Check
components.jsonbefore adding — it defines path aliases (@/components/ui) that must be respected asChildfor polymorphism — when a button needs to render as a<Link>, useasChildnot a wrapper div