425 lines
11 KiB
Markdown
425 lines
11 KiB
Markdown
# shadcn/ui Component Reference
|
|
|
|
Complete catalog of shadcn/ui components with usage patterns and installation.
|
|
|
|
## Installation
|
|
|
|
**Add specific components:**
|
|
```bash
|
|
npx shadcn@latest add button
|
|
npx shadcn@latest add button card dialog # Multiple
|
|
npx shadcn@latest add --all # All components
|
|
```
|
|
|
|
Components install to `components/ui/` with automatic dependency management.
|
|
|
|
## Form & Input Components
|
|
|
|
### Button
|
|
```tsx
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
<Button variant="default">Default</Button>
|
|
<Button variant="destructive">Delete</Button>
|
|
<Button variant="outline" size="sm">Small Outline</Button>
|
|
<Button variant="ghost" size="icon"><Icon /></Button>
|
|
<Button variant="link">Link Style</Button>
|
|
```
|
|
|
|
Variants: `default | destructive | outline | secondary | ghost | link`
|
|
Sizes: `default | sm | lg | icon`
|
|
|
|
### Input
|
|
```tsx
|
|
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>
|
|
```
|
|
|
|
### Form (with React Hook Form + Zod)
|
|
```tsx
|
|
import { useForm } from "react-hook-form"
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import * as z from "zod"
|
|
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
const schema = z.object({
|
|
username: z.string().min(2).max(50),
|
|
email: z.string().email()
|
|
})
|
|
|
|
function ProfileForm() {
|
|
const form = useForm({
|
|
resolver: zodResolver(schema),
|
|
defaultValues: { username: "", email: "" }
|
|
})
|
|
|
|
return (
|
|
<Form {...form}>
|
|
<form onSubmit={form.handleSubmit(console.log)} className="space-y-8">
|
|
<FormField control={form.control} name="username" render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Username</FormLabel>
|
|
<FormControl>
|
|
<Input placeholder="shadcn" {...field} />
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)} />
|
|
<Button type="submit">Submit</Button>
|
|
</form>
|
|
</Form>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Select
|
|
```tsx
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
|
|
<Select>
|
|
<SelectTrigger className="w-[180px]">
|
|
<SelectValue placeholder="Theme" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="light">Light</SelectItem>
|
|
<SelectItem value="dark">Dark</SelectItem>
|
|
<SelectItem value="system">System</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
```
|
|
|
|
### Checkbox
|
|
```tsx
|
|
import { Checkbox } from "@/components/ui/checkbox"
|
|
import { Label } from "@/components/ui/label"
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox id="terms" />
|
|
<Label htmlFor="terms">Accept terms</Label>
|
|
</div>
|
|
```
|
|
|
|
### Radio Group
|
|
```tsx
|
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
|
import { Label } from "@/components/ui/label"
|
|
|
|
<RadioGroup defaultValue="option-one">
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="option-one" id="option-one" />
|
|
<Label htmlFor="option-one">Option One</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="option-two" id="option-two" />
|
|
<Label htmlFor="option-two">Option Two</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
```
|
|
|
|
### Textarea
|
|
```tsx
|
|
import { Textarea } from "@/components/ui/textarea"
|
|
|
|
<Textarea placeholder="Type your message here." />
|
|
```
|
|
|
|
### Switch
|
|
```tsx
|
|
import { Switch } from "@/components/ui/switch"
|
|
import { Label } from "@/components/ui/label"
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Switch id="airplane-mode" />
|
|
<Label htmlFor="airplane-mode">Airplane Mode</Label>
|
|
</div>
|
|
```
|
|
|
|
### Date Picker
|
|
```tsx
|
|
import { Calendar } from "@/components/ui/calendar"
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
|
import { Button } from "@/components/ui/button"
|
|
import { CalendarIcon } from "lucide-react"
|
|
import { format } from "date-fns"
|
|
import { useState } from "react"
|
|
|
|
const [date, setDate] = useState<Date>()
|
|
|
|
<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>
|
|
```
|
|
|
|
## Layout & Navigation
|
|
|
|
### Card
|
|
```tsx
|
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Card Title</CardTitle>
|
|
<CardDescription>Card Description</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p>Card Content</p>
|
|
</CardContent>
|
|
<CardFooter>
|
|
<Button>Action</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
```
|
|
|
|
### Tabs
|
|
```tsx
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
|
|
<Tabs defaultValue="account">
|
|
<TabsList>
|
|
<TabsTrigger value="account">Account</TabsTrigger>
|
|
<TabsTrigger value="password">Password</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="account">Account settings</TabsContent>
|
|
<TabsContent value="password">Password settings</TabsContent>
|
|
</Tabs>
|
|
```
|
|
|
|
### Accordion
|
|
```tsx
|
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
|
|
|
<Accordion type="single" collapsible>
|
|
<AccordionItem value="item-1">
|
|
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
<AccordionContent>
|
|
Yes. It adheres to WAI-ARIA design pattern.
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
<AccordionItem value="item-2">
|
|
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
|
<AccordionContent>
|
|
Yes. Comes with default styles customizable with Tailwind.
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</Accordion>
|
|
```
|
|
|
|
### Navigation Menu
|
|
```tsx
|
|
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from "@/components/ui/navigation-menu"
|
|
|
|
<NavigationMenu>
|
|
<NavigationMenuList>
|
|
<NavigationMenuItem>
|
|
<NavigationMenuTrigger>Getting Started</NavigationMenuTrigger>
|
|
<NavigationMenuContent>
|
|
<NavigationMenuLink>Introduction</NavigationMenuLink>
|
|
<NavigationMenuLink>Installation</NavigationMenuLink>
|
|
</NavigationMenuContent>
|
|
</NavigationMenuItem>
|
|
</NavigationMenuList>
|
|
</NavigationMenu>
|
|
```
|
|
|
|
## Overlays & Dialogs
|
|
|
|
### Dialog
|
|
```tsx
|
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
|
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
<Button>Open</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Are you sure?</DialogTitle>
|
|
<DialogDescription>This action cannot be undone.</DialogDescription>
|
|
</DialogHeader>
|
|
</DialogContent>
|
|
</Dialog>
|
|
```
|
|
|
|
### Drawer
|
|
```tsx
|
|
import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer"
|
|
|
|
<Drawer>
|
|
<DrawerTrigger>Open</DrawerTrigger>
|
|
<DrawerContent>
|
|
<DrawerHeader>
|
|
<DrawerTitle>Title</DrawerTitle>
|
|
<DrawerDescription>Description</DrawerDescription>
|
|
</DrawerHeader>
|
|
<DrawerFooter>
|
|
<Button>Submit</Button>
|
|
<DrawerClose>Cancel</DrawerClose>
|
|
</DrawerFooter>
|
|
</DrawerContent>
|
|
</Drawer>
|
|
```
|
|
|
|
### Popover
|
|
```tsx
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
|
|
|
<Popover>
|
|
<PopoverTrigger>Open</PopoverTrigger>
|
|
<PopoverContent>Content here</PopoverContent>
|
|
</Popover>
|
|
```
|
|
|
|
### Toast
|
|
```tsx
|
|
import { useToast } from "@/hooks/use-toast"
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
const { toast } = useToast()
|
|
|
|
<Button onClick={() => {
|
|
toast({
|
|
title: "Scheduled: Catch up",
|
|
description: "Friday, February 10, 2023 at 5:57 PM"
|
|
})
|
|
}}>
|
|
Show Toast
|
|
</Button>
|
|
```
|
|
|
|
### Command
|
|
```tsx
|
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"
|
|
|
|
<Command>
|
|
<CommandInput placeholder="Type a command or search..." />
|
|
<CommandList>
|
|
<CommandEmpty>No results found.</CommandEmpty>
|
|
<CommandGroup heading="Suggestions">
|
|
<CommandItem>Calendar</CommandItem>
|
|
<CommandItem>Search Emoji</CommandItem>
|
|
<CommandItem>Calculator</CommandItem>
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
```
|
|
|
|
### Alert Dialog
|
|
```tsx
|
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
|
|
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button variant="destructive">Delete</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Absolutely sure?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
This permanently deletes your account and removes data from servers.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
<AlertDialogAction>Continue</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
```
|
|
|
|
## Feedback & Status
|
|
|
|
### Alert
|
|
```tsx
|
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
|
|
|
<Alert>
|
|
<AlertTitle>Heads up!</AlertTitle>
|
|
<AlertDescription>You can add components using CLI.</AlertDescription>
|
|
</Alert>
|
|
|
|
<Alert variant="destructive">
|
|
<AlertTitle>Error</AlertTitle>
|
|
<AlertDescription>Session expired. Please log in.</AlertDescription>
|
|
</Alert>
|
|
```
|
|
|
|
### Progress
|
|
```tsx
|
|
import { Progress } from "@/components/ui/progress"
|
|
|
|
<Progress value={33} />
|
|
```
|
|
|
|
### Skeleton
|
|
```tsx
|
|
import { Skeleton } from "@/components/ui/skeleton"
|
|
|
|
<div className="flex items-center space-x-4">
|
|
<Skeleton className="h-12 w-12 rounded-full" />
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-[250px]" />
|
|
<Skeleton className="h-4 w-[200px]" />
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
## Display Components
|
|
|
|
### Table
|
|
```tsx
|
|
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
|
|
<Table>
|
|
<TableCaption>Recent invoices</TableCaption>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Invoice</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Amount</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell>INV001</TableCell>
|
|
<TableCell>Paid</TableCell>
|
|
<TableCell>$250.00</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
```
|
|
|
|
### Avatar
|
|
```tsx
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
|
|
|
<Avatar>
|
|
<AvatarImage src="https://github.com/shadcn.png" />
|
|
<AvatarFallback>CN</AvatarFallback>
|
|
</Avatar>
|
|
```
|
|
|
|
### Badge
|
|
```tsx
|
|
import { Badge } from "@/components/ui/badge"
|
|
|
|
<Badge>Default</Badge>
|
|
<Badge variant="secondary">Secondary</Badge>
|
|
<Badge variant="destructive">Destructive</Badge>
|
|
<Badge variant="outline">Outline</Badge>
|
|
```
|