"I used to wait 3 months for Material UI to fix a bug. Now I fix it in 3 minutes."
shadcn/ui is not a library you install in package.json. It is a CLI that purely copies code into your project. You own the component. You own the styles. You own the bugs. This is the ultimate freedom for a frontend engineer.
We call it "The Copy/Paste Revolution". Instead of fighting with a black-box NPM package to change a border-radius, you just open the file and change the class. It builds upon Radix UI (Headless) and Tailwind CSS (Styling) to give you the best of both worlds: Accessibility and Customizability.
02. Headless Architecture
Separation of Concerns re-imagined. We separate the Behavior from the Style.
🧠 Radix UI (The Brain)
"I handle the open/close state, the collision detection, the focus trap, and the ARIA attributes. I am invisible."
🎨 Tailwind CSS (The Skin)
"I handle how it looks. I don't care if it's open or closed, I just style the `data-state` attribute."
03. Class Variance Authority (CVA)
How do we handle variants like `primary`, `secondary`, `outline`, or sizes like `sm`, `lg` without messy template literals? Enter cva. It's a schema for your CSS classes.
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 hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
04. CSS Variables: The Secret Sauce
Notice in the CVA example above, we use `bg-primary`, not `bg-blue-500`. This is because shadcn uses Semantic Tokens mapped to CSS Variables using HSL values.
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
}
.dark {
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
}
Pro Tip: This allows Dark Mode to work automatically without adding `dark:` modifiers everywhere. We just swap the values of the variables.
05. How the CLI Works
When you run `npx shadcn-ui@latest add button`, it does three simple things:
Fetch
Fetches the component code from the registry (GitHub raw files).
Check
Checks your `components.json` config to see where to put it.
Install
Installs any necessary dependencies (like `@radix-ui/react-slot`).
07. Theme Playground
Shadcn uses CSS variables for theming. Change the "Primary" color variable and watch the UI update globally.
System Radius & Color
This entire playground is driven by 2 React state variables that inject inline styles to mimic CSS variables.