| name | using-shadcn-ui |
| description | Use when building React UI components, implementing design systems, or needing pre-built accessible components - leverages shadcn/ui primitives and shadcnblocks.com (829 production-ready blocks) for rapid interface development |
Using shadcn/ui
Overview
shadcn/ui is a collection of re-usable, accessible React components built on Radix UI and Tailwind CSS. Unlike traditional component libraries, shadcn/ui copies components directly into your project, giving you full ownership and customization control.
Core principle: Components live in your codebase. You own the code. No package.json dependency.
When to Use
Use shadcn/ui when:
- Building React applications with Tailwind CSS
- Need accessible, customizable UI components
- Want pre-built patterns without library lock-in
- Implementing common UI patterns (forms, dialogs, dropdowns, etc.)
- Starting new projects that need design system foundation
- Need production-ready blocks for hero sections, pricing, testimonials, etc.
shadcnblocks.com integration:
- 829 blocks across 42 categories
- Production-ready sections (Hero, Navbar, Footer, Pricing, Testimonials, etc.)
- Copy-paste directly into your project
- Built with same shadcn/ui primitives
Don't use for:
- Non-React projects
- Projects without Tailwind CSS
- When you need a locked, versioned component library
- Simple HTML/CSS projects
Installation Workflow
1. Initialize shadcn/ui
npx shadcn@latest init
Configuration prompts:
- Style: Default or New York
- Color: Slate, Gray, Zinc, etc.
- CSS variables: Yes (recommended)
- Tailwind config: Use CSS variables for colors
2. Add Components
# Add specific components
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add form
# Add multiple at once
npx shadcn@latest add button card dialog dropdown-menu
Components install to: components/ui/
3. Using shadcnblocks.com
Visit: https://www.shadcnblocks.com/blocks
Workflow:
- Browse category (Hero, Pricing, Testimonial, etc.)
- Find desired block
- Click "Copy Code"
- Paste into your component file
- Install any missing shadcn/ui dependencies
- Customize colors, text, and layout
Component Categories Reference
| Category | Common Use Cases | Example Components |
|---|---|---|
| Forms | User input, validation | Input, Textarea, Select, Checkbox, Radio Group |
| Overlays | Modals, popovers | Dialog, Popover, Tooltip, Sheet |
| Navigation | Menus, dropdowns | Dropdown Menu, Navigation Menu, Tabs |
| Feedback | User notifications | Alert, Toast, Progress, Skeleton |
| Data Display | Tables, cards, badges | Table, Card, Badge, Avatar |
| Layout | Containers, separators | Separator, Aspect Ratio, Scroll Area |
shadcnblocks.com Categories (829 blocks)
Layout & Navigation (200 blocks)
- Hero (162 blocks): Landing page headers with CTAs
- Navbar (13 blocks): Navigation headers
- Footer (18 blocks): Page footers
- Banner (7 blocks): Announcement bars
Content Sections (367 blocks)
- Feature (266 blocks): Product feature showcases
- Blog (22 blocks): Blog layouts and cards
- Gallery (47 blocks): Image galleries
- Timeline (14 blocks): Event timelines
- Team (10 blocks): Team member profiles
- About (10 blocks): About us sections
Business Components (116 blocks)
- Pricing (35 blocks): Pricing tables and cards
- Testimonial (28 blocks): Customer testimonials
- Case Studies (9 blocks): Success stories
- Integration (16 blocks): Integration showcases
- Service/Services (21 blocks): Service offerings
- Stats (17 blocks): Statistics displays
User Engagement (64 blocks)
- CTA (25 blocks): Call-to-action sections
- Contact (13 blocks): Contact forms
- Signup/Login (17 blocks): Authentication forms
- Waitlist (2 blocks): Email capture
- Community (7 blocks): Community features
Information Display (82 blocks)
- FAQ (15 blocks): Frequently asked questions
- Comparison (10 blocks): Feature comparisons
- Logos (11 blocks): Logo grids
- Resources (4 blocks): Resource libraries
- Download (12 blocks): Download sections
- Changelog (7 blocks): Update logs
- Careers (9 blocks): Job listings
- Compliance (3 blocks): Legal/privacy sections
Quick Start Example
// 1. Add button component
// $ npx shadcn@latest add button
// 2. Import and use
import { Button } from "@/components/ui/button"
export function MyComponent() {
return (
<div>
<Button variant="default">Click me</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Cancel</Button>
<Button variant="ghost">Subtle</Button>
</div>
)
}
Form Pattern with shadcn/ui
// Install: npx shadcn@latest add form input button
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
const formSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
})
export function LoginForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
})
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="you@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Sign In</Button>
</form>
</Form>
)
}
Dialog/Modal Pattern
// Install: npx shadcn@latest add dialog button
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
export function ConfirmDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">Delete Account</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</DialogDescription>
</DialogHeader>
<div className="flex justify-end gap-3">
<Button variant="outline">Cancel</Button>
<Button variant="destructive">Delete</Button>
</div>
</DialogContent>
</Dialog>
)
}
Using Blocks from shadcnblocks.com
Example: Adding a Hero Section
1. Visit: https://www.shadcnblocks.com/blocks 2. Navigate to: Hero category 3. Select a design 4. Click "Copy Code" 5. Create component:
// app/components/hero.tsx
// (Paste copied code from shadcnblocks.com)
import { Button } from "@/components/ui/button"
export function Hero() {
return (
<section className="container flex flex-col items-center gap-8 pt-20 pb-12">
<h1 className="text-6xl font-bold text-center">
Build amazing products
</h1>
<p className="text-xl text-muted-foreground text-center max-w-2xl">
Get started with production-ready components built with shadcn/ui
</p>
<div className="flex gap-4">
<Button size="lg">Get Started</Button>
<Button size="lg" variant="outline">Learn More</Button>
</div>
</section>
)
}
6. Install missing components:
npx shadcn@latest add button
7. Import and use:
import { Hero } from "@/components/hero"
export default function Home() {
return <Hero />
}
Example: Adding a Pricing Section
// Install: npx shadcn@latest add card button badge
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
export function Pricing() {
return (
<section className="container py-20">
<h2 className="text-4xl font-bold text-center mb-12">
Simple, transparent pricing
</h2>
<div className="grid md:grid-cols-3 gap-8">
<Card>
<CardHeader>
<CardTitle>Starter</CardTitle>
<CardDescription>Perfect for trying out</CardDescription>
</CardHeader>
<CardContent>
<div className="text-4xl font-bold mb-2">$9</div>
<p className="text-sm text-muted-foreground">per month</p>
</CardContent>
<CardFooter>
<Button className="w-full">Get Started</Button>
</CardFooter>
</Card>
<Card className="border-primary">
<CardHeader>
<Badge className="w-fit mb-2">Most Popular</Badge>
<CardTitle>Pro</CardTitle>
<CardDescription>For growing businesses</CardDescription>
</CardHeader>
<CardContent>
<div className="text-4xl font-bold mb-2">$29</div>
<p className="text-sm text-muted-foreground">per month</p>
</CardContent>
<CardFooter>
<Button className="w-full">Get Started</Button>
</CardFooter>
</Card>
<Card>
<CardHeader>
<CardTitle>Enterprise</CardTitle>
<CardDescription>For large organizations</CardDescription>
</CardHeader>
<CardContent>
<div className="text-4xl font-bold mb-2">Custom</div>
<p className="text-sm text-muted-foreground">contact us</p>
</CardContent>
<CardFooter>
<Button className="w-full" variant="outline">Contact Sales</Button>
</CardFooter>
</Card>
</div>
</section>
)
}
Customization
Theme Colors
Edit app/globals.css or styles/globals.css:
@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%;
/* ... more CSS variables */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... dark mode colors */
}
}
Component Variants
Components use class-variance-authority for variants:
import { Button } from "@/components/ui/button"
// Available variants:
<Button variant="default">Default</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
// Available sizes:
<Button size="default">Default</Button>
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
<Button size="icon">Icon</Button>
Extending Components
Edit the component file directly in components/ui/:
// components/ui/button.tsx
const buttonVariants = cva(
"inline-flex items-center justify-center...",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground...",
destructive: "bg-destructive text-destructive-foreground...",
// Add custom variant:
success: "bg-green-600 text-white hover:bg-green-700",
},
// ... rest of variants
}
}
)
Common Patterns
Loading States
import { Button } from "@/components/ui/button"
import { Loader2 } from "lucide-react"
export function LoadingButton() {
const [isLoading, setIsLoading] = useState(false)
return (
<Button disabled={isLoading}>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{isLoading ? "Loading..." : "Submit"}
</Button>
)
}
Toast Notifications
// Install: npx shadcn@latest add toast
import { useToast } from "@/hooks/use-toast"
import { Button } from "@/components/ui/button"
export function ToastExample() {
const { toast } = useToast()
return (
<Button
onClick={() => {
toast({
title: "Success!",
description: "Your changes have been saved.",
})
}}
>
Show Toast
</Button>
)
}
Data Tables
// Install: npx shadcn@latest add table
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
const invoices = [
{ invoice: "INV001", status: "Paid", amount: "$250.00" },
{ invoice: "INV002", status: "Pending", amount: "$150.00" },
]
export function InvoiceTable() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell>{invoice.invoice}</TableCell>
<TableCell>{invoice.status}</TableCell>
<TableCell>{invoice.amount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)
}
Common Mistakes
| Mistake | Fix |
|---|---|
| Installing as npm package | shadcn/ui copies code. Run npx shadcn@latest add [component] |
Importing from shadcn |
Import from @/components/ui/[component] |
| Not installing dependencies | Each component may need additional packages (listed in CLI) |
| Modifying in node_modules | Components live in your components/ui/ - edit directly |
| Forgetting Tailwind config | Run npx shadcn@latest init to configure properly |
| Skipping shadcnblocks.com | Don't build common sections from scratch - use 829 ready blocks |
Workflow Summary
Starting new project:
npx shadcn@latest init- Add needed components:
npx shadcn@latest add button card dialog - Browse shadcnblocks.com for section blocks
- Copy blocks, install dependencies, customize
Adding new feature:
- Identify needed components (form, dialog, etc.)
npx shadcn@latest add [components]- Check shadcnblocks.com for similar patterns
- Build or adapt from block
- Customize colors and content
Customizing:
- Edit component files in
components/ui/directly - Modify
globals.cssfor theme colors - Add variants using
class-variance-authoritypatterns
Resources
- Official Docs: https://ui.shadcn.com
- shadcnblocks.com: https://www.shadcnblocks.com/blocks (829 blocks)
- Components: https://ui.shadcn.com/docs/components
- Themes: https://ui.shadcn.com/themes
- Examples: https://ui.shadcn.com/examples
Integration with Other Tools
Works seamlessly with:
- Next.js (App Router or Pages)
- Remix
- Astro
- Vite + React
- React Hook Form
- Zod validation
- Tailwind CSS
- Radix UI (under the hood)