A developer told me: 'I installed Material UI. My bundle grew by 200KB. I needed to customize one button — it took 3 hours fighting CSS overrides.' Shadcn UI is different: you copy the component code into your project. It's YOUR code. Style it however you want.
What Shadcn UI Offers
Shadcn UI (open source, free):
- 50+ components — buttons, dialogs, tables, forms, charts, etc.
- Copy-paste — components are YOUR code, not a dependency
- Tailwind CSS — style with utility classes
- Radix UI primitives — accessible, composable
- Dark mode — built-in theme switching
- TypeScript — full type safety
-
CLI —
npx shadcn@latest add button— adds component to your project - Customizable — change anything, no CSS overrides
Quick Start
# Initialize in your Next.js/Vite project
npx shadcn@latest init
# Add components
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add dialog
npx shadcn@latest add table
npx shadcn@latest add form
Usage
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
function Dashboard() {
return (
<div className="grid gap-4 md:grid-cols-3">
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium">Total Revenue</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">$45,231.89</div>
<p className="text-xs text-muted-foreground">+20.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium">Active Users</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">2,350</div>
<Badge variant="secondary">+180 this week</Badge>
</CardContent>
</Card>
</div>
);
}
Data Table
import { DataTable } from '@/components/ui/data-table';
import { ColumnDef } from '@tanstack/react-table';
const columns: ColumnDef<User>[] = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => (
<Badge variant={row.getValue('status') === 'active' ? 'default' : 'secondary'}>
{row.getValue('status')}
</Badge>
)
},
{
id: 'actions',
cell: ({ row }) => (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon"><MoreHorizontal /></Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
];
function UsersPage() {
return <DataTable columns={columns} data={users} />;
}
Dialog (Modal)
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
function CreateUserDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Create User</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>New User</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="Alice Johnson" />
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="alice@example.com" />
</div>
</div>
<Button type="submit">Create</Button>
</DialogContent>
</Dialog>
);
}
Theme Customization
/* globals.css — customize the entire theme */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--border: 214.3 31.8% 91.4%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
}
}
Why Shadcn UI
| Shadcn UI | MUI/Chakra/Ant Design |
|---|---|
| Code in your project | External dependency |
| Zero runtime | 100-200KB bundle |
| Full customization | Override styles |
| Tailwind CSS | CSS-in-JS |
| Copy what you need | Install entire library |
Building data dashboards? Check out my web scraping actors on Apify — structured data for your tables.
Need a custom UI? Email me at spinov001@gmail.com.
Top comments (0)