shadcn/ui: Building a Design System Without Writing a Design System
Component libraries trap you in their styling system. shadcn/ui copies components directly into your project — you own the code, Tailwind handles the styling, and customization is just editing a file.
What Makes It Different
| Traditional Library | shadcn/ui |
|---|---|
| Installed as npm package | Copied into your src/ |
| Styled by the library | Styled with Tailwind in your code |
| Limited customization | Full control, it's your file |
| Version lock-in | No lock-in, it's your code |
Setup
npx shadcn@latest init
# Choose: TypeScript, Tailwind, CSS variables
# Sets up components.json and globals.css
Add Components
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add form
npx shadcn@latest add table
npx shadcn@latest add toast
Each command copies the component to src/components/ui/.
Usage
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
export function ConfirmDialog({ onConfirm }: { onConfirm: () => void }) {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Delete Account</Button>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
</DialogHeader>
<p className='text-sm text-muted-foreground'>
This action cannot be undone.
</p>
<div className='flex gap-2 justify-end'>
<Button variant='outline' onClick={() => setOpen(false)}>Cancel</Button>
<Button variant='destructive' onClick={onConfirm}>Delete</Button>
</div>
</DialogContent>
</Dialog>
</>
);
}
Form with Validation
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
const schema = z.object({ email: z.string().email() });
function EmailForm() {
const form = useForm({ resolver: zodResolver(schema) });
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(console.log)}>
<FormField control={form.control} name='email' render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<Button type='submit'>Subscribe</Button>
</form>
</Form>
);
}
Theming
/* globals.css — change these to retheme everything */
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
}
Available Components
Accordion, Alert, Avatar, Badge, Button, Calendar, Card, Checkbox, Command, DataTable, DatePicker, Dialog, Dropdown Menu, Form, Input, Label, Popover, Progress, Radio Group, Select, Separator, Sheet, Skeleton, Slider, Switch, Table, Tabs, Textarea, Toast, Toggle, Tooltip.
Full shadcn/ui component library ships in the AI SaaS Starter Kit — dashboard, landing page, and auth forms all built with shadcn. $99 at whoffagents.com.
Top comments (0)