Skip to content

shadcn/ui Library

A comprehensive collection of 40+ production-ready React components built on Radix UI primitives with Tailwind CSS styling, providing accessibility, customization, and enterprise-grade quality.

shadcn/ui Radix UI 40+ Components TypeScript
  • Radix UI Primitives - Unstyled, accessible components as foundation
  • Class Variance Authority (CVA) - Type-safe variant management
  • Tailwind CSS - Utility-first styling with design tokens
  • TypeScript-First - Full type safety and IntelliSense
  • Composable Design - Flexible component composition patterns

Form & Input

12 Components: Button, Input, Select, Checkbox, Radio, Form, Label, Textarea, Switch, Slider, Date Picker, Time Picker

Layout & Structure

10 Components: Card, Dialog, Sheet, Accordion, Tabs, Separator, Aspect Ratio, Scroll Area, Resizable, Collapsible

Navigation

8 Components: Navigation Menu, Breadcrumb, Pagination, Command, Context Menu, Dropdown Menu, Menubar, Sidebar

Feedback & Status

10+ Components: Alert, Badge, Progress, Skeleton, Toast, Alert Dialog, Hover Card, Popover, Tooltip, Avatar

The Button component uses CVA for type-safe variant management with multiple styles and sizes.

Button Component Usage
import { Button } from '@/components/ui/button'
// Basic button usage
export default function ButtonExample() {
return (
<div className="flex items-center gap-4">
{/* Default primary button */}
<Button>Primary Action</Button>
{/* Variant examples */}
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link Style</Button>
<Button variant="destructive">Delete</Button>
{/* Size variations */}
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">🚀</Button>
</div>
)
}
// Button with asChild pattern (renders as different element)
import { Link } from 'react-router-dom'
<Button asChild>
<Link to="/dashboard">Go to Dashboard</Link>
</Button>
// Loading state pattern
<Button disabled={isLoading}>
{isLoading && <LoadingSpinner className="mr-2" />}
{isLoading ? 'Saving...' : 'Save Changes'}
</Button>

The Card components provide a flexible layout system with multiple composition options.

Card Component System
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
CardAction,
} from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
// Basic card structure
export default function UserCard({ user }) {
return (
<Card>
<CardHeader>
<CardTitle>{user.name}</CardTitle>
<CardDescription>{user.email}</CardDescription>
<CardAction>
<Badge variant="secondary">{user.role}</Badge>
</CardAction>
</CardHeader>
<CardContent>
<div className="space-y-2">
<p className="text-sm">
<strong>Department:</strong> {user.department}
</p>
<p className="text-sm">
<strong>Joined:</strong> {formatDate(user.joinedDate)}
</p>
</div>
</CardContent>
<CardFooter className="gap-2">
<Button variant="outline" size="sm">
View Profile
</Button>
<Button size="sm">
Edit User
</Button>
</CardFooter>
</Card>
)
}
// Dashboard stats card
function StatsCard({ title, value, change, trend }) {
return (
<Card>
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
</CardHeader>
<CardContent className="pb-3">
<div className="text-2xl font-bold">{value}</div>
<p className="text-xs text-muted-foreground">
<span className={trend === 'up' ? 'text-green-600' : 'text-red-600'}>
{change}
</span>{' '}
from last month
</p>
</CardContent>
</Card>
)
}

Form components with built-in validation states and accessibility features.

Form Components Usage
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Checkbox } from '@/components/ui/checkbox'
import { Switch } from '@/components/ui/switch'
// Complete form example
export default function ContactForm() {
return (
<form className="space-y-6">
{/* Text Input */}
<div className="space-y-2">
<Label htmlFor="name">Full Name</Label>
<Input
id="name"
placeholder="Enter your full name"
aria-invalid={errors.name ? 'true' : 'false'}
/>
</div>
{/* Email Input */}
<div className="space-y-2">
<Label htmlFor="email">Email Address</Label>
<Input
id="email"
type="email"
placeholder="[email protected]"
aria-describedby="email-error"
/>
</div>
{/* Select Dropdown */}
<div className="space-y-2">
<Label htmlFor="department">Department</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select department" />
</SelectTrigger>
<SelectContent>
<SelectItem value="engineering">Engineering</SelectItem>
<SelectItem value="design">Design</SelectItem>
<SelectItem value="marketing">Marketing</SelectItem>
<SelectItem value="sales">Sales</SelectItem>
</SelectContent>
</Select>
</div>
{/* Textarea */}
<div className="space-y-2">
<Label htmlFor="message">Message</Label>
<Textarea
id="message"
placeholder="Enter your message here..."
rows={4}
/>
</div>
{/* Checkbox */}
<div className="flex items-center space-x-2">
<Checkbox id="newsletter" />
<Label htmlFor="newsletter" className="text-sm">
Subscribe to our newsletter
</Label>
</div>
{/* Switch */}
<div className="flex items-center space-x-2">
<Switch id="notifications" />
<Label htmlFor="notifications" className="text-sm">
Enable notifications
</Label>
</div>
<Button type="submit" className="w-full">
Submit Form
</Button>
</form>
)
}

Accessible dialog components with flexible composition patterns.

Dialog Component System
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
// User management dialog
export default function UserDialog({ user, onSave }) {
const [open, setOpen] = useState(false)
const [formData, setFormData] = useState(user)
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline">Edit User</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit User Profile</DialogTitle>
<DialogDescription>
Make changes to the user profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input
id="name"
value={formData.name}
onChange={(e) => setFormData(prev => ({
...prev,
name: e.target.value
}))}
className="col-span-3"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="email" className="text-right">
Email
</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) => setFormData(prev => ({
...prev,
email: e.target.value
}))}
className="col-span-3"
/>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setOpen(false)}
>
Cancel
</Button>
<Button
onClick={() => {
onSave(formData)
setOpen(false)
}}
>
Save Changes
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
// Confirmation dialog
function DeleteConfirmDialog({ itemName, onConfirm }) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive" size="sm">Delete</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete{' '}
<strong>{itemName}</strong> and remove all associated data.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button variant="destructive" onClick={onConfirm}>
Delete Permanently
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}

Flexible badge system for status indicators and labels.

Badge & Status Components
import { Badge } from '@/components/ui/badge'
import { Progress } from '@/components/ui/progress'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
// Status badges with variants
export default function StatusExamples() {
return (
<div className="space-y-6">
{/* Basic badges */}
<div className="flex items-center gap-2">
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Error</Badge>
<Badge variant="outline">Outline</Badge>
</div>
{/* Status indicators */}
<div className="flex items-center gap-3">
<Badge variant="secondary" className="bg-green-100 text-green-800">
✓ Active
</Badge>
<Badge variant="secondary" className="bg-yellow-100 text-yellow-800">
⏳ Pending
</Badge>
<Badge variant="destructive">
✗ Inactive
</Badge>
</div>
{/* User status with avatar */}
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage src="/avatars/01.png" alt="User" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div>
<p className="font-medium">John Doe</p>
<div className="flex items-center gap-2">
<Badge variant="outline" className="text-xs">
🟢 Online
</Badge>
<span className="text-xs text-muted-foreground">
Last seen 2 minutes ago
</span>
</div>
</div>
</div>
{/* Progress with label */}
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>Upload Progress</span>
<span>75%</span>
</div>
<Progress value={75} className="h-2" />
</div>
</div>
)
}
// Dynamic status badge component
function StatusBadge({ status, ...props }) {
const variants = {
active: { variant: 'default', children: '✓ Active' },
pending: {
variant: 'secondary',
className: 'bg-yellow-100 text-yellow-800',
children: '⏳ Pending'
},
inactive: { variant: 'destructive', children: '✗ Inactive' },
}
const badgeProps = variants[status] || variants.inactive
return <Badge {...badgeProps} {...props} />
}

Accessible navigation components for complex user interfaces.

Navigation Components
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
NavigationMenuViewport,
} from '@/components/ui/navigation-menu'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/components/ui/breadcrumb'
// Main navigation menu
export default function MainNavigation() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<li className="row-span-3">
<NavigationMenuLink asChild>
<a
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
href="/"
>
<div className="mb-2 mt-4 text-lg font-medium">
Our Platform
</div>
<p className="text-sm leading-tight text-muted-foreground">
Comprehensive admin dashboard solution for modern applications.
</p>
</a>
</NavigationMenuLink>
</li>
<ListItem href="/dashboard" title="Dashboard">
Analytics and overview of your application
</ListItem>
<ListItem href="/users" title="User Management">
Manage users, roles, and permissions
</ListItem>
<ListItem href="/settings" title="Settings">
Configure your application settings
</ListItem>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Documentation</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
<ListItem title="Getting Started" href="/docs">
Installation and setup guide
</ListItem>
<ListItem title="Components" href="/docs/components">
Reusable UI components library
</ListItem>
<ListItem title="API Reference" href="/docs/api">
Complete API documentation
</ListItem>
<ListItem title="Examples" href="/docs/examples">
Implementation examples and patterns
</ListItem>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/contact">
Contact
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
)
}
// Breadcrumb navigation
function PageBreadcrumb({ items }) {
return (
<Breadcrumb>
<BreadcrumbList>
{items.map((item, index) => (
<React.Fragment key={item.href}>
<BreadcrumbItem>
{index === items.length - 1 ? (
<BreadcrumbPage>{item.label}</BreadcrumbPage>
) : (
<BreadcrumbLink href={item.href}>
{item.label}
</BreadcrumbLink>
)}
</BreadcrumbItem>
{index < items.length - 1 && <BreadcrumbSeparator />}
</React.Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
)
}
// Usage example
<PageBreadcrumb
items={[
{ label: 'Dashboard', href: '/dashboard' },
{ label: 'Users', href: '/dashboard/users' },
{ label: 'Profile', href: '/dashboard/users/profile' },
]}
/>

Components for presenting structured data and information.

Data Display Components
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
// Data table example
export default function UsersTable({ users }) {
return (
<Table>
<TableCaption>A list of your recent users.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">ID</TableHead>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Role</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell className="font-medium">{user.id}</TableCell>
<TableCell>{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>
<Badge variant="secondary">{user.role}</Badge>
</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm">Edit</Button>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={4}>Total Users</TableCell>
<TableCell className="text-right">{users.length}</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}
// Tabs for organized content
function UserProfileTabs({ user }) {
return (
<Tabs defaultValue="profile" className="w-full">
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="profile">Profile</TabsTrigger>
<TabsTrigger value="activity">Activity</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="profile" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Personal Information</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
<p><strong>Name:</strong> {user.name}</p>
<p><strong>Email:</strong> {user.email}</p>
<p><strong>Department:</strong> {user.department}</p>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="activity" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Recent Activity</CardTitle>
</CardHeader>
<CardContent>
{/* Activity timeline */}
</CardContent>
</Card>
</TabsContent>
<TabsContent value="settings" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Account Settings</CardTitle>
</CardHeader>
<CardContent>
{/* Settings form */}
</CardContent>
</Card>
</TabsContent>
</Tabs>
)
}
// FAQ Accordion
function FAQSection({ faqs }) {
return (
<Accordion type="single" collapsible className="w-full">
{faqs.map((faq, index) => (
<AccordionItem key={index} value={`item-${index}`}>
<AccordionTrigger className="text-left">
{faq.question}
</AccordionTrigger>
<AccordionContent>
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
)
}
Custom Variant Creation
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
// Create custom component with variants
const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
{
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
warning:
"border-yellow-500/50 text-yellow-900 dark:text-yellow-100 bg-yellow-50 dark:bg-yellow-900/10",
success:
"border-green-500/50 text-green-900 dark:text-green-100 bg-green-50 dark:bg-green-900/10",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Alert({
className,
variant,
...props
}: React.HTMLAttributes<HTMLDivElement> &
VariantProps<typeof alertVariants>) {
return (
<div
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
)
}
// Usage with different variants
<Alert variant="success">
<CheckIcon className="h-4 w-4" />
<AlertTitle>Success!</AlertTitle>
<AlertDescription>Your changes have been saved successfully.</AlertDescription>
</Alert>
Compound Component Patterns
// Create compound component for complex UI patterns
function DataCard({ children, ...props }) {
return (
<Card {...props}>
{children}
</Card>
)
}
function DataCardHeader({ title, description, action }) {
return (
<CardHeader>
<CardTitle>{title}</CardTitle>
{description && <CardDescription>{description}</CardDescription>}
{action && <CardAction>{action}</CardAction>}
</CardHeader>
)
}
function DataCardMetrics({ metrics }) {
return (
<CardContent>
<div className="grid grid-cols-2 gap-4">
{metrics.map((metric, index) => (
<div key={index} className="space-y-1">
<p className="text-2xl font-bold">{metric.value}</p>
<p className="text-xs text-muted-foreground">{metric.label}</p>
</div>
))}
</div>
</CardContent>
)
}
// Compound component usage
<DataCard>
<DataCardHeader
title="User Analytics"
description="Last 30 days"
action={<Button variant="outline" size="sm">Export</Button>}
/>
<DataCardMetrics
metrics={[
{ label: 'Total Users', value: '2,345' },
{ label: 'Active Users', value: '1,987' },
{ label: 'New Signups', value: '234' },
{ label: 'Retention Rate', value: '84.5%' },
]}
/>
</DataCard>
Accessibility Features
// Components include accessibility features by default:
// Screen reader support
<Button aria-label="Delete user account">
<TrashIcon />
</Button>
// Keyboard navigation
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
{/* Focus trap and ESC key handling built-in */}
<DialogTitle>Confirm Action</DialogTitle>
<DialogDescription>
This action cannot be undone.
</DialogDescription>
</DialogContent>
</Dialog>
// Form validation states
<Input
aria-invalid={hasError}
aria-describedby="error-message"
/>
{hasError && (
<p id="error-message" className="text-sm text-destructive">
This field is required
</p>
)}
// Loading states
<Button disabled={isLoading} aria-busy={isLoading}>
{isLoading && <Spinner className="mr-2" aria-hidden />}
{isLoading ? 'Saving...' : 'Save'}
</Button>
PropTypeDescription
classNamestringAdditional CSS classes
asChildbooleanRender as child element (Slot pattern)
variantstringComponent variant (when applicable)
sizestringComponent size (when applicable)
disabledbooleanDisable interaction

Components using Class Variance Authority include:

ComponentVariantsSizes
Buttondefault, destructive, outline, secondary, ghost, linkdefault, sm, lg, icon
Badgedefault, secondary, destructive, outline-
Alertdefault, destructive-

The shadcn/ui library provides a complete design system with 40+ accessible, customizable components for building professional React applications! 🎨✨