shadcn-ui-designer
Skill1 starsChanged 11 months agoMITView on GitHub
Design and build modern UI components and pages using shadcn/ui. Creates clean, accessible interfaces with Tailwind CSS following shadcn principles. Use when building UI components, pages, forms, dashboards, or any interface work.
In this repository4 other files it gives its agents.
- article-extractorSkill
- brainstormingSkill
- expo-ios-designingSkill
- frontend-designSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 62
Use consistent spacing scale:
- Distinctive: line 79
Use semantic color tokens:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Shadcn UI Designer
Build production-ready UI components using shadcn/ui principles: minimal, accessible, composable, and beautiful by default.
Core Philosophy
Design modern, minimal interfaces with:
- Clean typography (Inter/system fonts, 2-3 weights max)
- Ample whitespace (4px-based spacing: p-1 through p-8)
- Subtle shadows (shadow-sm/md/lg only)
- Accessible contrast (WCAG AA minimum)
- Smooth micro-interactions (200-300ms transitions)
- Professional neutrals (slate/zinc scale) with subtle accents
Build composable components that work together seamlessly.
Quick Start Pattern
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
export function MyComponent() {
return (
<div className="container mx-auto p-6 space-y-6">
<div className="space-y-2">
<h1 className="text-2xl font-semibold">Title</h1>
<p className="text-sm text-muted-foreground">Description</p>
</div>
<Card className="shadow-sm">
<CardHeader>
<CardTitle>Section</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Content here */}
</CardContent>
</Card>
</div>
)
}Design System Rules
Typography
- Hierarchy:
text-2xl(headings) →text-base(body) →text-sm(secondary) - Weights:
font-semibold(600) for emphasis,font-medium(500) for labels,font-normal(400) for body - Colors:
text-foreground(primary),text-muted-foreground(secondary)
<h1 className="text-2xl font-semibold">Page Title</h1>
<p className="text-muted-foreground">Supporting text</p>Spacing
Use consistent spacing scale:
- Micro:
space-y-2(8px) - within sections - Small:
space-y-4(16px) - between elements - Medium:
space-y-6(24px) - between sections - Large:
space-y-8(32px) - major divisions
<div className="container mx-auto p-6 space-y-6">
<section className="space-y-4">
<div className="space-y-2">
{/* Related elements */}
</div>
</section>
</div>Colors
Use semantic color tokens:
- Background:
bg-background,bg-card,bg-muted - Foreground:
text-foreground,text-muted-foreground - Borders:
border-border,border-input - Primary:
bg-primary,text-primary-foreground - Destructive:
bg-destructive,text-destructive-foreground
<Card className="bg-card text-card-foreground border-border">
<Button className="bg-primary text-primary-foreground">
Primary Action
</Button>
<div className="bg-muted/50 text-muted-foreground">
Subtle highlight
</div>
</Card>Shadows & Elevation
Three levels only:
shadow-sm: Cards, raised sections (0 1px 2px)shadow-md: Dropdowns, popovers (0 4px 6px)shadow-lg: Modals, dialogs (0 10px 15px)
<Card className="shadow-sm hover:shadow-md transition-shadow" />Animations
- Duration: 200-300ms
- Easing: ease-in-out
- Use cases: Hover states, loading states, reveals
<Button className="transition-colors duration-200 hover:bg-primary/90">
<Card className="transition-all duration-200 hover:shadow-md hover:scale-[1.02]">Accessibility
Always include:
- Semantic HTML (
<main>,<nav>,<article>) - ARIA labels on icons/actions
- Focus states (
:focus-visible:ring-2) - Keyboard navigation
- WCAG AA contrast (4.5:1 minimum)
<button
aria-label="Close dialog"
className="focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2"
>
<X className="h-4 w-4" />
</button>Component Patterns
Dashboard Cards
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{stats.map(stat => (
<Card key={stat.id} className="shadow-sm">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium">
{stat.label}
</CardTitle>
{stat.icon}
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stat.value}</div>
<p className="text-xs text-muted-foreground">
{stat.change}
</p>
</CardContent>
</Card>
))}
</div>Forms
<form className="space-y-6">
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="name">Full Name</Label>
<Input
id="name"
placeholder="Enter your name"
className="max-w-md"
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="name@example.com"
className="max-w-md"
/>
</div>
</div>
<div className="flex gap-3">
<Button type="submit">Submit</Button>
<Button type="button" variant="outline">Cancel</Button>
</div>
</form>Data Tables
<Card className="shadow-sm">
<CardHeader>
<CardTitle>Recent Orders</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Order</TableHead>
<TableHead>Customer</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{orders.map(order => (
<TableRow
key={order.id}
className="hover:bg-muted/50 transition-colors"
>
<TableCell className="font-medium">{order.id}</TableCell>
<TableCell>{order.customer}</TableCell>
<TableCell>
<Badge variant={order.statusVariant}>
{order.status}
</Badge>
</TableCell>
<TableCell className="text-right">
{order.amount}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>Modals/Dialogs
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit Profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when done.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
{/* Form fields */}
</div>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>Loading States
// Skeleton loading
<Card className="shadow-sm">
<CardHeader>
<Skeleton className="h-4 w-[200px]" />
</CardHeader>
<CardContent className="space-y-3">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-[80%]" />
</CardContent>
</Card>
// Loading button
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>Empty States
<Card className="shadow-sm">
<CardContent className="flex flex-col items-center justify-center py-12 space-y-3">
<div className="p-4 bg-muted rounded-full">
<FileX className="h-8 w-8 text-muted-foreground" />
</div>
<div className="text-center space-y-1">
<h3 className="font-semibold">No results found</h3>
<p className="text-sm text-muted-foreground">
Try adjusting your search
</p>
</div>
<Button variant="outline" size="sm">
Clear filters
</Button>
</CardContent>
</Card>Layout Patterns
Container Widths
// Full width with constraints
<div className="container mx-auto px-4 max-w-7xl">
// Content-focused (prose)
<div className="container mx-auto px-4 max-w-3xl">
// Form-focused
<div className="container mx-auto px-4 max-w-2xl">Responsive Grids
// Dashboard grid
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
// Content + sidebar
<div className="grid gap-6 lg:grid-cols-[1fr_300px]">
<main>{/* Content */}</main>
<aside>{/* Sidebar */}</aside>
</div>
// Two column split
<div className="grid gap-6 md:grid-cols-2">Navigation
<header className="border-b border-border">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-6">
<Logo />
<nav className="hidden md:flex gap-6">
<a href="#" className="text-sm font-medium transition-colors hover:text-primary">
Dashboard
</a>
<a href="#" className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground">
Projects
</a>
</nav>
</div>
<div className="flex items-center gap-4">
<Button variant="ghost" size="sm">
<Bell className="h-4 w-4" />
</Button>
<Avatar>
<AvatarImage src={user.avatar} />
<AvatarFallback>{user.initials}</AvatarFallback>
</Avatar>
</div>
</div>
</header>Best Practices
Component Organization
// ✅ Good: Small, focused components
export function UserCard({ user }) {
return (
<Card>
<CardHeader>
<UserAvatar user={user} />
<UserDetails user={user} />
</CardHeader>
</Card>
)
}
// ❌ Avoid: Large monolithic components
export function DashboardPage() {
// 500 lines of JSX...
}Composability
// ✅ Compose shadcn components
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Share</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-destructive">
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>State Management
// Form state
const [formData, setFormData] = useState({ name: '', email: '' })
// Loading states
const [isLoading, setIsLoading] = useState(false)
// UI states
const [isOpen, setIsOpen] = useState(false)Error Handling
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
className={errors.email ? "border-destructive" : ""}
/>
{errors.email && (
<p className="text-sm text-destructive">{errors.email}</p>
)}
</div>
</form>Common Shadcn Components
Essential Components
- Layout: Card, Tabs, Sheet, Dialog, Popover, Separator
- Forms: Input, Textarea, Select, Checkbox, Radio, Switch, Label
- Buttons: Button, Toggle, ToggleGroup
- Display: Badge, Avatar, Skeleton, Table
- Feedback: Alert, Toast, Progress
- Navigation: NavigationMenu, DropdownMenu, Command
Button Variants
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="destructive">Delete</Button>Badge Variants
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="destructive">Error</Badge>Workflow
- Understand requirements - What component/page is needed?
- Choose components - Which shadcn/ui components fit?
- Build structure - Layout and hierarchy first
- Apply styling - Typography, spacing, colors
- Add interactions - Hover states, transitions, focus
- Ensure accessibility - ARIA, keyboard, contrast
- Test responsive - Mobile, tablet, desktop
Quality Checklist
Before completing:
- Uses shadcn/ui components appropriately
- Follows 4px spacing scale (p-2, p-4, p-6, etc.)
- Uses semantic color tokens (bg-card, text-foreground, etc.)
- Limited shadow usage (shadow-sm/md/lg only)
- Smooth transitions (200-300ms duration)
- ARIA labels on interactive elements
- Keyboard focus visible (ring-2 ring-primary)
- WCAG AA contrast ratios
- Mobile-responsive layout
- Loading and error states handled
References
- Shadcn UI - Component library
- Tailwind CSS - Utility classes
- WCAG 2.1 - Accessibility standards
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

