Common UI component patterns with Tailwind CSS + Shadcn/ui examples.
import { Button } from "@/components/ui/button"
<Button className="bg-blue-600 hover:bg-blue-700">
Click Me
</Button>
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button variant="default">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete</Button>
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Processing...
</Button>
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content</p>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Settings</CardTitle>
</CardHeader>
<CardContent>
<p>Configure your preferences</p>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="ghost">Cancel</Button>
<Button>Save</Button>
</CardFooter>
</Card>
<Card className="transition-all hover:shadow-lg hover:scale-105">
<CardHeader>
<CardTitle>Hover Me</CardTitle>
</CardHeader>
<CardContent>
<p>This card responds to hover</p>
</CardContent>
</Card>
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="you@example.com"
/>
</div>
import { Textarea } from "@/components/ui/textarea"
<div className="space-y-2">
<Label htmlFor="message">Message</Label>
<Textarea
id="message"
placeholder="Type your message here"
rows={4}
/>
</div>
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
<Select>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select option" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Option 1</SelectItem>
<SelectItem value="option2">Option 2</SelectItem>
<SelectItem value="option3">Option 3</SelectItem>
</SelectContent>
</Select>
import { Checkbox } from "@/components/ui/checkbox"
<div className="flex items-center space-x-2">
<Checkbox id="terms" />
<Label htmlFor="terms">Accept terms and conditions</Label>
</div>
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
<RadioGroup defaultValue="option1">
<div className="flex items-center space-x-2">
<RadioGroupItem value="option1" id="option1" />
<Label htmlFor="option1">Option 1</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="option2" id="option2" />
<Label htmlFor="option2">Option 2</Label>
</div>
</RadioGroup>
<nav className="flex items-center justify-between px-6 py-4 border-b">
<div className="text-2xl font-bold">Logo</div>
<div className="flex gap-6">
<a href="/home" className="hover:text-blue-600 transition-colors">Home</a>
<a href="/about" className="hover:text-blue-600 transition-colors">About</a>
<a href="/contact" className="hover:text-blue-600 transition-colors">Contact</a>
</div>
<Button>Sign In</Button>
</nav>
<aside className="w-64 h-screen border-r p-6">
<div className="text-xl font-bold mb-8">Dashboard</div>
<nav className="space-y-2">
<a href="#" className="flex items-center gap-3 px-4 py-2 rounded-lg hover:bg-gray-100">
<HomeIcon className="w-5 h-5" />
<span>Home</span>
</a>
<a href="#" className="flex items-center gap-3 px-4 py-2 rounded-lg hover:bg-gray-100">
<SettingsIcon className="w-5 h-5" />
<span>Settings</span>
</a>
</nav>
</aside>
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
<TabsTrigger value="tab3">Tab 3</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Tab 1 content</TabsContent>
<TabsContent value="tab2">Tab 2 content</TabsContent>
<TabsContent value="tab3">Tab 3 content</TabsContent>
</Tabs>
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
This action cannot be undone.
</DialogDescription>
</DialogHeader>
<div className="flex justify-end gap-2 mt-4">
<Button variant="ghost">Cancel</Button>
<Button variant="destructive">Confirm</Button>
</div>
</DialogContent>
</Dialog>
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete Account</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your account.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>John Doe</TableCell>
<TableCell>john@example.com</TableCell>
<TableCell>Active</TableCell>
</TableRow>
</TableBody>
</Table>
import { Badge } from "@/components/ui/badge"
<Badge>New</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="destructive">Error</Badge>
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
"use client"
import { useState } from "react"
import { Upload } from "lucide-react"
export function FileUpload() {
const [isDragging, setIsDragging] = useState(false)
return (
<div
onDragOver={(e) => {
e.preventDefault()
setIsDragging(true)
}}
onDragLeave={() => setIsDragging(false)}
onDrop={(e) => {
e.preventDefault()
setIsDragging(false)
// Handle file drop
}}
className={`
border-2 border-dashed rounded-lg p-12 text-center
transition-colors cursor-pointer
${isDragging ? 'border-blue-500 bg-blue-50' : 'border-gray-300'}
`}
>
<Upload className="w-12 h-12 mx-auto mb-4 text-gray-400" />
<p className="text-lg font-medium">Drop files here or click to upload</p>
<p className="text-sm text-gray-500 mt-2">PNG, JPG, GIF up to 10MB</p>
</div>
)
}
import { Calendar } from "@/components/ui/calendar"
import { useState } from "react"
const [date, setDate] = useState<Date | undefined>(new Date())
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-md border"
/>
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Calendar } from "@/components/ui/calendar"
import { CalendarIcon } from "lucide-react"
import { format } from "date-fns"
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : "Pick a date"}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={date}
onSelect={setDate}
/>
</PopoverContent>
</Popover>
import { useToast } from "@/components/ui/use-toast"
const { toast } = useToast()
<Button
onClick={() => {
toast({
title: "Success!",
description: "Your changes have been saved.",
})
}}
>
Show Toast
</Button>
// Success
toast({
title: "Success",
description: "Operation completed successfully",
})
// Error
toast({
variant: "destructive",
title: "Error",
description: "Something went wrong",
})
// With Action
toast({
title: "Email sent",
description: "Check your inbox",
action: <Button size="sm">Undo</Button>,
})
import { Skeleton } from "@/components/ui/skeleton"
<div className="space-y-4">
<Skeleton className="h-12 w-full" />
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
</div>
import { Loader2 } from "lucide-react"
<div className="flex items-center justify-center h-screen">
<Loader2 className="w-8 h-8 animate-spin text-blue-600" />
</div>
import { Progress } from "@/components/ui/progress"
<Progress value={60} className="w-full" />
"use client"
import { Menu, X } from "lucide-react"
import { useState } from "react"
export function MobileNav() {
const [isOpen, setIsOpen] = useState(false)
return (
<>
<button onClick={() => setIsOpen(!isOpen)} className="md:hidden">
{isOpen ? <X /> : <Menu />}
</button>
{isOpen && (
<div className="md:hidden absolute top-16 left-0 right-0 bg-white border-b p-4">
<nav className="flex flex-col gap-4">
<a href="#">Home</a>
<a href="#">About</a>
<a href="#">Contact</a>
</nav>
</div>
)}
</>
)
}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<Card>Item 1</Card>
<Card>Item 2</Card>
<Card>Item 3</Card>
</div>
Component Library: Shadcn/ui (https://ui.shadcn.com)
Styling: Tailwind CSS (https://tailwindcss.com)
Icons: Lucide React (https://lucide.dev)