
Frontend Design
- 27 installs
- 10 repo stars
- Updated July 24, 2026
- duyet/claude-plugins
Create distinctive, production-grade React/Next.js interfaces that avoid generic AI-slop aesthetics - component architecture, performance patterns and state management.
About
A frontend-design skill for creating distinctive, production-grade interfaces with React and Next.js - it pushes for bold aesthetic direction, real working code, strong component architecture, performance patterns and sound state management, deliberately avoiding generic 'AI slop' looks. A solo builder reaches for it when building UI components, landing pages, dashboards or design systems where visual quality actually matters.
- Distinctive, production-grade React/Next.js UI
- Component architecture and state management
- Performance patterns, avoids generic AI aesthetics
Frontend Design by the numbers
- 27 all-time installs (skills.sh)
- Ranked #1,480 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/duyet/claude-plugins --skill frontend-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 27 |
|---|---|
| repo stars | ★ 10 |
| Last updated | July 24, 2026 |
| Repository | duyet/claude-plugins ↗ |
What it does
Create distinctive, production-grade React/Next.js interfaces that avoid generic AI-slop aesthetics - component architecture, performance patterns and state management.
Who is it for?
High-quality web UI and landing pages
Skip if: Backend-only work
Files
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
When to Invoke This Skill
Automatically activate for:
- Building UI components, pages, dashboards, or applications
- Creating landing pages, forms, or interactive interfaces
- Designing data visualizations or charts
- Implementing design systems or component libraries
- Any frontend work where visual quality matters
Design Thinking
Before coding, understand the context and commit to a BOLD aesthetic direction:
1. Purpose: What problem does this interface solve? Who uses it? 2. Tone: Pick a distinctive aesthetic:
- Brutally minimal | Maximalist chaos | Retro-futuristic
- Organic/natural | Luxury/refined | Playful/toy-like
- Editorial/magazine | Brutalist/raw | Art deco/geometric
- Soft/pastel | Industrial/utilitarian | Neo-brutalist
- Swiss/grid-based | Cyberpunk/neon | Scandinavian/calm
3. Constraints: Technical requirements (framework, performance, accessibility) 4. Differentiation: What makes this UNFORGETTABLE?
CRITICAL: Choose a clear conceptual direction and execute it with precision.
Technology Stack Preferences
Component Libraries (Priority Order)
1. shadcn/ui - First choice for React projects. Copy components, full customization. 2. Radix UI - Accessible primitives when shadcn isn't available 3. Headless UI - For Tailwind-based projects 4. Custom CSS - When libraries aren't appropriate
Data Visualization
1. Recharts - First choice for charts in React. Clean, composable, customizable. 2. Tremor - Dashboard-ready charts with great defaults 3. Victory - When Recharts doesn't fit 4. D3.js - For complex, custom visualizations only
Styling
1. Tailwind CSS - Utility-first, consistent spacing/colors 2. CSS Variables - For theming and design tokens 3. CSS Modules - When Tailwind isn't available
Animation
1. Framer Motion - First choice for React animations 2. CSS animations - For simple, performant effects 3. GSAP - For complex timeline animations
Anti-Slop Design Rules
NEVER Use These (AI Slop Indicators)
Typography Slop:
- Inter, Roboto, Arial, system-ui as primary fonts
- Font sizes that are too uniform (everything 14-16px)
- Generic font pairings (Inter + Inter)
Color Slop:
- Purple/violet gradients on white backgrounds
- Blue-to-purple CTA buttons
- Washed-out, low-contrast color schemes
- Rainbow gradients for no reason
- Generic blue (#3B82F6) as primary color
Layout Slop:
- Perfectly centered everything
- Cards with equal rounded corners (rounded-lg everywhere)
- Symmetric layouts with no visual hierarchy
- Grid of 3-4 identical cards pattern
- Hero with centered text + gradient background + floating shapes
Component Slop:
- Glassmorphism on everything
- Shadows that are too soft and uniform
- Generic avatar circles with gradient backgrounds
- Empty state illustrations that are too cute
- Progress bars with gradient fills
Animation Slop:
- Fade-in on scroll for everything
- Bounce effects on buttons
- Spinning loaders when skeleton screens work better
- Hover effects that all feel the same
INSTEAD, Create Distinctive Design
Typography That Stands Out:
Display fonts: Clash Display, Cabinet Grotesk, Satoshi, Space Grotesk (sparingly),
Instrument Serif, Fraunces, Playfair Display, Editorial New
Body fonts: Geist, Plus Jakarta Sans, DM Sans, Source Serif Pro, Literata
Monospace: JetBrains Mono, Fira Code, IBM Plex Mono- Create contrast between display and body fonts
- Use larger type than feels comfortable (48px+ for headlines)
- Vary font weights dramatically (300 vs 700)
Color With Intent:
- Pick ONE dominant color and use it sparingly
- Use near-black (#0A0A0A, #111111) instead of pure black
- Create depth with subtle gradients in backgrounds
- Use color for meaning, not decoration
- Consider dark mode as primary (not afterthought)
Layouts That Break the Grid:
- Asymmetric compositions with clear hierarchy
- Overlapping elements that create depth
- Generous negative space OR intentional density
- Grid-breaking hero elements
- Varying content widths within the same page
Components With Character:
- Micro-interactions that feel tactile
- Loading states that match the brand
- Error states that are helpful and on-brand
- Empty states that guide rather than decorate
- Form inputs that feel substantial
React Component Architecture
Design components like you are the creator of React. Think in composition, reusability, and elegance.
Component Philosophy
Small, Focused Components:
- Each component does ONE thing well
- Prefer 20-50 lines per component
- If a component exceeds 100 lines, split it
- Name components by what they ARE, not what they DO
Composition Over Configuration:
// BAD: Monolithic component with many props
<Card
title="User Profile"
subtitle="Settings"
avatar={user.avatar}
showBadge={true}
badgeColor="green"
actions={[...]}
/>
// GOOD: Composable components
<Card>
<Card.Header>
<Avatar src={user.avatar} />
<Card.Title>User Profile</Card.Title>
<Badge variant="success" />
</Card.Header>
<Card.Content>...</Card.Content>
<Card.Actions>...</Card.Actions>
</Card>Props Design Principles
Meaningful, Typed Props:
// Generic, reusable props
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
disabled?: boolean;
children: React.ReactNode;
}
// State props that tell a story
interface DataTableProps<T> {
data: T[];
columns: Column<T>[];
isLoading?: boolean;
isEmpty?: boolean;
onRowClick?: (row: T) => void;
selectedRows?: Set<string>;
}Prop Patterns:
- Use
childrenfor content (notcontentprop) - Use render props for customization:
renderItem,renderEmpty - Use compound patterns for complex UIs
- Avoid boolean props when variants work better
State Management
Local State First:
// Keep state as close to where it's used as possible
function SearchInput({ onSearch }: { onSearch: (query: string) => void }) {
const [query, setQuery] = useState('');
const debouncedSearch = useDebouncedCallback(onSearch, 300);
return (
<Input
value={query}
onChange={(e) => {
setQuery(e.target.value);
debouncedSearch(e.target.value);
}}
/>
);
}Lift State Only When Needed:
- Lift when siblings need to share state
- Lift when parent needs to control behavior
- Don't lift "just in case"
Component Patterns
1. Container/Presenter Pattern:
// Container: handles data fetching, state
function UserProfileContainer({ userId }: { userId: string }) {
const { data: user, isLoading } = useUser(userId);
if (isLoading) return <UserProfileSkeleton />;
return <UserProfile user={user} />;
}
// Presenter: pure UI, receives props
function UserProfile({ user }: { user: User }) {
return (
<Card>
<Avatar src={user.avatar} />
<h2>{user.name}</h2>
</Card>
);
}2. Compound Components:
// Parent provides context
const TabsContext = createContext<TabsContextValue>(null);
function Tabs({ children, defaultValue }: TabsProps) {
const [active, setActive] = useState(defaultValue);
return (
<TabsContext.Provider value={{ active, setActive }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
}
Tabs.List = TabsList;
Tabs.Tab = Tab;
Tabs.Panel = TabPanel;
// Usage
<Tabs defaultValue="overview">
<Tabs.List>
<Tabs.Tab value="overview">Overview</Tabs.Tab>
<Tabs.Tab value="settings">Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="overview">...</Tabs.Panel>
</Tabs>3. Render Props for Flexibility:
interface ListProps<T> {
items: T[];
renderItem: (item: T, index: number) => React.ReactNode;
renderEmpty?: () => React.ReactNode;
keyExtractor: (item: T) => string;
}
function List<T>({ items, renderItem, renderEmpty, keyExtractor }: ListProps<T>) {
if (items.length === 0 && renderEmpty) return renderEmpty();
return (
<ul>
{items.map((item, i) => (
<li key={keyExtractor(item)}>{renderItem(item, i)}</li>
))}
</ul>
);
}File Organization
components/
├── ui/ # Primitive components (Button, Input, Card)
│ ├── button.tsx
│ ├── input.tsx
│ └── card.tsx
├── patterns/ # Composed patterns (DataTable, Form, Modal)
│ ├── data-table/
│ │ ├── data-table.tsx
│ │ ├── data-table-header.tsx
│ │ ├── data-table-row.tsx
│ │ └── index.ts
│ └── form/
├── features/ # Feature-specific components
│ ├── dashboard/
│ └── settings/
└── layouts/ # Page layouts
├── sidebar-layout.tsx
└── centered-layout.tsxAnti-Patterns to Avoid
Component Slop:
- Giant 500+ line components
- Props drilling through 5+ levels
useEffectfor everything- Inline styles mixed with Tailwind
anytypes on props
Instead:
- Split into smaller, focused components
- Use Context or composition for deep data
- Prefer derived state over effects
- Consistent styling approach
- Strict TypeScript types
shadcn/ui Quick Reference
Core Philosophy: shadcn/ui is NOT a component library—it's how you build your component library. You get actual component code that you own and can modify.
Quick Start
# Initialize shadcn/ui
npx shadcn@latest init
# Add components
npx shadcn@latest add button card dialog
# Search registry
npx shadcn@latest search @shadcn -q "button"Key Principles
1. Open Code: Full transparency, easy customization, AI-readable 2. Composition: Common, composable interface across all components 3. Distribution: Flat-file schema + CLI for easy installation 4. Beautiful Defaults: Great design out-of-the-box, easily customizable 5. AI-Ready: Open code structure for LLMs to understand and improve
Component Categories
| Category | Components |
|---|---|
| Form & Input | Form, Field, Button, Input, Textarea, Checkbox, Radio, Select, Switch, Slider, Calendar, Date Picker, Combobox |
| Layout & Navigation | Accordion, Breadcrumb, Navigation Menu, Sidebar, Tabs, Separator, Scroll Area, Resizable |
| Overlays & Dialogs | Dialog, Alert Dialog, Sheet, Drawer, Popover, Tooltip, Hover Card, Context Menu, Dropdown Menu, Command |
| Feedback & Status | Alert, Toast, Progress, Spinner, Skeleton, Badge, Empty |
| Display & Media | Avatar, Card, Table, Data Table, Chart, Carousel, Aspect Ratio, Typography |
Theming Basics
// Color convention: background + foreground
<div className="bg-background text-foreground">Hello</div>
<div className="bg-primary text-primary-foreground">Primary</div>
<div className="bg-muted text-muted-foreground">Muted</div>Customization Tips
1. Customize the theme - Don't use defaults
:root {
--radius: 0.5rem; /* or 0 for sharp corners */
--primary: 220 13% 10%; /* custom primary */
}2. Extend components - Add custom variants, modify animations, adjust spacing
3. Combine primitives - Layer components for unique effects
For Complete Documentation
See references/shadcn.md for:
- Complete components.json configuration
- Full theming system with CSS variables
- Dark mode setup guide
- CLI commands reference
- MCP server integration
- Registry schema for publishing components
Recharts Quick Reference
When creating charts:
1. Style the chart to match the UI
<ResponsiveContainer>
<LineChart data={data}>
<Line
type="monotone"
strokeWidth={2}
dot={false}
stroke="hsl(var(--primary))"
/>
<XAxis
tickLine={false}
axisLine={false}
tick={{ fill: 'hsl(var(--muted-foreground))' }}
/>
</LineChart>
</ResponsiveContainer>2. Remove visual clutter
- Hide axis lines when not needed
- Use subtle grid lines or none
- Custom tooltips that match your design
3. Add meaningful interactions
- Hover states that reveal detail
- Click handlers for drill-down
- Animate data changes smoothly
Implementation Checklist
Before considering frontend work complete:
- [ ] Typography creates clear hierarchy (display vs body)
- [ ] Colors are intentional and consistent (CSS variables)
- [ ] Spacing follows a rhythm (8px/4px grid)
- [ ] Interactive elements have hover/focus/active states
- [ ] Loading and empty states exist
- [ ] Dark mode works (if applicable)
- [ ] Animations are smooth (60fps, no jank)
- [ ] Accessibility: keyboard navigation, ARIA labels, color contrast
- [ ] Mobile responsive (or explicitly desktop-only)
- [ ] Code is production-ready (no console logs, proper error handling)
Output Format
When implementing frontend:
1. Explain the aesthetic direction (2-3 sentences) 2. List key design decisions (typography, colors, key components) 3. Provide complete, working code with:
- All imports and dependencies noted
- CSS/Tailwind classes included
- TypeScript types when applicable
- Comments for non-obvious choices
Remember: Claude is capable of extraordinary creative work. Commit fully to a distinctive vision that could only have been designed for this specific context.
Micro-Interaction Polish
The difference between good and exceptional interfaces lies in microscopic details that users feel but don't consciously notice. These patterns make interfaces feel "expensive" and polished.
1. Typography Enhancement
Text Wrapping for Headlines:
/* Prevents awkward widows in headlines */
.hero-title {
text-wrap: balance; /* Optimizes line breaks for headlines */
}
/* For multi-line text where you want pretty breaks */
.description {
text-wrap: pretty; /* Last line minimum 4 characters */
}- Use
balancefor headlines, titles, and short text blocks - Use
prettyfor descriptions, summaries, and body text where you want to avoid orphans
Font Smoothing:
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}- Critical for Mac rendering—removes "thin" look from fonts
- Makes text appear more substantial and premium
- Apply globally to
bodyor typography containers
Tabular Numbers:
.price, .metric, .stat {
font-variant-numeric: tabular-nums;
}- Essential for data, prices, metrics—prevents jitter when numbers animate
- Use for anything that changes value dynamically
- Avoids visual shifting during countdowns, tickers, or live data
2. Border Radius Consistency
Concentric Formula:
/* Outer radius = Inner radius + padding */
.card {
padding: 1.5rem;
border-radius: 16px;
}
.card-inner {
border-radius: calc(16px - 1.5rem); /* Concentric borders align perfectly */
}- When nesting elements with borders, adjust inner radius by subtracting padding
- Creates perfect alignment between concentric rounded corners
- Prevents "thick border" appearance at corners
3. Icon Animation Patterns
Contextual Icon States:
.icon {
transition: all 0.2s ease;
opacity: 0.6;
transform: scale(1);
}
.icon:hover {
opacity: 1;
transform: scale(1.1);
}
.icon.active {
opacity: 1;
transform: scale(1);
filter: drop-shadow(0 0 8px currentColor);
}- Icons should breathe: subtle scale + opacity changes
- Use
filter: drop-shadow()instead ofbox-shadowfor icons (respects shape) - Keep animations under 200ms for responsive feel
4. Animation Philosophy
Interruptible Animations:
/* GOOD: CSS transitions—user can interrupt */
.button {
transition: transform 0.2s ease, opacity 0.2s ease;
}
.button:hover {
transform: translateY(-2px);
}
/* AVOID: Keyframes for interactions—can't be interrupted */
@keyframes slideUp {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}- Use CSS transitions for user-triggered animations (hover, click, focus)
- Transitions can be interrupted when user moves away/clicks quickly
- Reserve keyframes for continuous, non-interactive animations (loaders, backgrounds)
Split and Stagger Enter:
/* Elements enter from different directions */
.card:nth-child(3n+1) { animation: slideFromLeft 0.4s ease forwards; }
.card:nth-child(3n+2) { animation: slideFromBottom 0.4s ease forwards; }
.card:nth-child(3n+3) { animation: slideFromRight 0.4s ease forwards; }
/* Stagger with delay */
.card:nth-child(1) { animation-delay: 0ms; }
.card:nth-child(2) { animation-delay: 50ms; }
.card:nth-child(3) { animation-delay: 100ms; }- Vary entrance directions based on position for visual interest
- Stagger delays: 50-100ms between elements feels premium, not sluggish
- Never exceed 300ms total delay—users hate waiting for content
Subtle Exit Animations:
.modal.closing {
animation: fadeOut 0.15s ease forwards;
}
@keyframes fadeOut {
to { opacity: 0; transform: scale(0.98); }
}- Exits should be faster than enters (150ms vs 300-400ms)
- Users want to dismiss things quickly
- Skip exit animations if it delays navigation
5. Alignment Precision
Optical vs Geometric Alignment:
/* Geometric center looks "off" with triangle icons */
.icon-triangle {
transform: translateY(-1px); /* Nudge down for optical center */
}
/* Circles appear smaller than squares at same size */
.icon-circle {
transform: scale(1.1); /* Slight scale for visual balance */
}- Trust your eyes, not the grid
- Triangles, stars, and irregular shapes need optical adjustment
- Different shapes at same "size" need visual balancing
- Test: squint—if something feels off, adjust by 1-2px
6. Depth Without Borders
Shadows Over Borders:
.card {
/* Instead of: border: 1px solid #e5e5e5; */
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08),
0 1px 2px rgba(0, 0, 0, 0.04);
}
.card-elevated {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
}- Shadows create depth without harsh edges
- Layer multiple shadows for subtle, natural elevation
- Borders can look "flat" or "boxed in"
- Exception: use borders for grouping, dividers, or interactive states
Image Outlines:
.image-container {
position: relative;
}
.image-container::after {
content: '';
position: absolute;
inset: 0;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: inherit;
pointer-events: none;
}- Ultra-subtle 1px border at 10% opacity adds polish to images
- Creates clean separation without visual weight
- Use on images, cards, or featured content
- In dark mode, use white with low opacity; light mode, use black
7. Micro-Interaction Timing
/* Fast interactions feel responsive */
.fast-interaction { transition-duration: 150ms; }
/* Standard interactions feel smooth */
.standard-interaction { transition-duration: 200ms; }
/* Slow animations feel deliberate */
.deliberate-motion { transition-duration: 400ms; }- 150ms: hover states, button clicks, toggle switches
- 200ms: card lifts, dropdown opens, tooltip appears
- 400ms+: page transitions, modal enters, complex animations
- Never use 1s+ for anything—feels sluggish
Micro-Interaction Checklist
Before shipping UI:
- [ ] Headlines use
text-wrap: balance - [ ] Font smoothing is applied (
antialiased) - [ ] Numbers/data use
tabular-nums - [ ] Concentric borders align (radius - padding formula)
- [ ] Icons breathe (scale + opacity on hover)
- [ ] User interactions use transitions (not keyframes)
- [ ] Entrance animations are split/staggered
- [ ] Exit animations are faster than enter
- [ ] Irregular icons are optically aligned
- [ ] Depth uses shadows (not borders)
- [ ] Images have ultra-subtle outlines
- [ ] Animation timing feels responsive (≤200ms for interactions)
shadcn/ui Reference
shadcn/ui is NOT a component library—it's how you build your component library. You get actual component code that you own and can modify.
Core Principles
1. Open Code: Full transparency, easy customization, AI-readable 2. Composition: Common, composable interface across all components 3. Distribution: Flat-file schema + CLI for easy installation 4. Beautiful Defaults: Great design out-of-the-box, easily customizable 5. AI-Ready: Open code structure for LLMs to understand and improve
Installation & Setup
# Using npx (npm)
npx shadcn@latest init
# Using bunx (bun)
bunx shadcn@latest init
# Using pnpm
pnpm dlx shadcn@latest init
# Using yarn
yarn dlx shadcn@latest initOr with your package manager's equivalent:
# Add components
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add button card dialog
# View component before installing
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view button card
# Search registry
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn -q "button"components.json Configuration
The components.json file controls how shadcn/ui integrates with your project:
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york", // Design style (cannot change after init)
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "neutral", // neutral, gray, zinc, stone, slate
"cssVariables": true, // Use CSS variables for theming
"prefix": "" // Tailwind prefix if needed
},
"rsc": true, // React Server Components support
"tsx": true, // TypeScript vs JavaScript
"aliases": {
"utils": "@/lib/utils",
"components": "@/components",
"ui": "@/components/ui", // Where UI components are installed
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": { // Multiple registry support
"@shadcn": "https://ui.shadcn.com/r/{name}.json",
"@v0": "https://v0.dev/chat/b/{name}"
}
}Configuration Fields
| Field | Description | Cannot Change After Init |
|---|---|---|
style | Design style variant | Yes |
tailwind.baseColor | Base color palette | Yes |
tailwind.cssVariables | Use CSS variables vs utilities | Yes |
tailwind.prefix | Tailwind class prefix | No |
rsc | React Server Components | No |
tsx | TypeScript vs JavaScript | No |
Theming System
Color Convention
Simple background and foreground pattern:
// Background and foreground colors
<div className="bg-background text-foreground">Hello</div>
<div className="bg-primary text-primary-foreground">Primary</div>
<div className="bg-muted text-muted-foreground">Muted</div>The background suffix is omitted when the variable is used for the background color of the component.
CSS Variables (Recommended)
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.269 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.371 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.439 0 0);
}Adding Custom Colors
:root {
--warning: oklch(0.84 0.16 84);
--warning-foreground: oklch(0.28 0.07 46);
}
.dark {
--warning: oklch(0.41 0.11 46);
--warning-foreground: oklch(0.99 0.02 95);
}
@theme inline {
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
}
/* Usage */
<div className="bg-warning text-warning-foreground" />Base Color Options
Available base colors for tailwind.baseColor:
| Color | Description |
|---|---|
neutral | Pure grayscale, no hue bias |
gray | Slightly cool gray with blue tint |
zinc | Cool gray with slight purple/blue tint |
stone | Warm gray with yellow/beige tint |
slate | Cool gray with strong blue tint |
Utility Classes vs CSS Variables
CSS Variables (Recommended):
<div className="bg-background text-foreground" />Utility Classes:
<div className="bg-zinc-950 dark:bg-white dark:text-zinc-950" />Set tailwind.cssVariables: false in components.json to use utility classes.
Dark Mode Setup (Next.js)
1. Install next-themes
# npm
npm install next-themes
# bun
bun add next-themes
# pnpm
pnpm add next-themes
# yarn
yarn add next-themes2. Create Theme Provider
// components/theme-provider.tsx
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}3. Wrap Root Layout
// app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider"
export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
)
}The suppressHydrationWarning prop is required on the html tag to prevent hydration mismatch warnings when rendering theme classes.
Component Categories
Form & Input
| Component | Description | Dependencies |
|---|---|---|
| Form | Building forms with React Hook Form + Zod validation | react-hook-form, zod |
| Field | Field component with labels and error messages | - |
| Button | Button with multiple variants | - |
| Button Group | Group multiple buttons together | - |
| Input | Text input component | - |
| Input Group | Input with prefix/suffix addons | - |
| Input OTP | One-time password input | input-otp |
| Textarea | Multi-line text input | - |
| Checkbox | Checkbox input | @radix-ui/react-checkbox |
| Radio Group | Radio button group | @radix-ui/react-radio-group |
| Select | Select dropdown | @radix-ui/react-select |
| Switch | Toggle switch | @radix-ui/react-switch |
| Slider | Slider input | @radix-ui/react-slider |
| Calendar | Calendar for date selection | react-day-picker |
| Date Picker | Date picker combining input + calendar | calendar |
| Combobox | Searchable select with autocomplete | cmdk |
| Label | Form label | - |
Layout & Navigation
| Component | Description | Dependencies |
|---|---|---|
| Accordion | Collapsible accordion | @radix-ui/react-accordion |
| Breadcrumb | Breadcrumb navigation | - |
| Navigation Menu | Accessible nav with dropdowns | @radix-ui/react-navigation-menu |
| Sidebar | Collapsible sidebar for layouts | - |
| Tabs | Tabbed interface | @radix-ui/react-tabs |
| Separator | Visual divider | - |
| Scroll Area | Custom scrollable area | @radix-ui/react-scroll-area |
| Resizable | Resizable panel layout | react-resizable-panels |
Overlays & Dialogs
| Component | Description | Dependencies |
|---|---|---|
| Dialog | Modal dialog | @radix-ui/react-dialog |
| Alert Dialog | Confirmation dialog | @radix-ui/react-alert-dialog |
| Sheet | Slide-out panel (drawer) | @radix-ui/react-dialog |
| Drawer | Mobile-friendly drawer | vaul |
| Popover | Floating popover | @radix-ui/react-popover |
| Tooltip | Tooltip for additional context | @radix-ui/react-tooltip |
| Hover Card | Card that appears on hover | @radix-ui/react-hover-card |
| Context Menu | Right-click context menu | @radix-ui/react-context-menu |
| Dropdown Menu | Dropdown menu | @radix-ui/react-dropdown-menu |
| Menubar | Horizontal menubar | @radix-ui/react-menubar |
| Command | Command palette | cmdk |
Feedback & Status
| Component | Description | Dependencies |
|---|---|---|
| Alert | Alert for messages/notifications | - |
| Toast | Toast notifications | sonner |
| Progress | Progress bar | @radix-ui/react-progress |
| Spinner | Loading spinner | - |
| Skeleton | Skeleton loading placeholder | - |
| Badge | Badge for labels/status | - |
| Empty | Empty state component | - |
Display & Media
| Component | Description | Dependencies |
|---|---|---|
| Avatar | Avatar for user profiles | @radix-ui/react-avatar |
| Card | Card container | - |
| Table | Table for displaying data | - |
| Data Table | Advanced table (sorting, filtering, pagination) | tanstack-table |
| Chart | Charts using Recharts | recharts |
| Carousel | Carousel using Embla | embla-carousel-react |
| Aspect Ratio | Container with aspect ratio | @radix-ui/react-aspect-ratio |
| Typography | Typography styles | - |
| Item | Generic item for lists/menus | - |
| Kbd | Keyboard shortcut display | - |
MCP Server Integration
The shadcn MCP Server allows AI assistants to browse, search, and install components from registries using natural language.
What is MCP?
Model Context Protocol (MCP) is an open protocol that enables AI assistants to securely connect to external data sources and tools. With the shadcn MCP server, your AI assistant gains direct access to:
- Browse Components - List all available components, blocks, and templates from any configured registry
- Search Across Registries - Find specific components by name or functionality across multiple sources
- Install with Natural Language - Add components using simple conversational prompts like "add a login form"
- Support for Multiple Registries - Access public registries, private company libraries, and third-party sources
Quick Start
Run the MCP init command in your project:
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest mcp init --client claudeRestart your MCP client and try prompts like:
- "Show me all available components in the shadcn registry"
- "Add the button, dialog and card components to my project"
- "Create a contact form using components from the shadcn registry"
Supported clients: --client claude|cursor|vscode|codex
Configuration
Claude Code
Add to .mcp.json in your project:
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}Restart Claude Code and run /mcp to verify connection.
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}Enable the shadcn MCP server in Cursor Settings.
VS Code (GitHub Copilot)
Add to .vscode/mcp.json:
{
"servers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}Open .vscode/mcp.json and click Start next to the shadcn server.
Codex
Add to ~/.codex/config.toml:
[mcp_servers.shadcn]
command = "npx"
args = ["shadcn@latest", "mcp"]Restart Codex to load the MCP server.
Registry Configuration
Configure multiple registries in your components.json:
{
"registries": {
"@shadcn": "https://ui.shadcn.com/r/{name}.json",
"@v0": "https://v0.dev/chat/b/{name}",
"@acme": "https://registry.acme.com/{name}.json",
"@private": {
"url": "https://api.company.com/registry/{name}.json",
"headers": {
"Authorization": "Bearer ${REGISTRY_TOKEN}",
"X-API-Key": "${API_KEY}"
},
"params": {
"version": "latest"
}
}
}
}Environment variables in ${VAR_NAME} format are automatically expanded.
Authentication
For private registries, set environment variables in .env.local:
REGISTRY_TOKEN=your_token_here
API_KEY=your_api_key_hereExample Prompts
Once configured, use natural language to interact with registries:
Browse & Search:
- "Show me all available components in the shadcn registry"
- "Find me a login form from the shadcn registry"
Install Items:
- "Add the button component to my project"
- "Create a login form using shadcn components"
- "Install the Cursor rules from the acme registry"
Work with Namespaces:
- "Show me components from acme registry"
- "Install @internal/auth-form"
- "Build a landing page using hero, features and testimonials from the acme registry"
Installing from Registries (CLI)
# Install from public registry
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @shadcn/button
# Install from v0
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @v0/dashboard
# Install from private registry with auth
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @private/button
# Install multiple resources
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @acme/header @internal/auth-utilsTroubleshooting
MCP Not Responding: 1. Check configuration is properly enabled in your MCP client 2. Restart MCP client after configuration changes 3. Ensure shadcn is installed in your project 4. Confirm network access to configured registries
Registry Access Issues: 1. Verify registry URLs are correct in components.json 2. Ensure environment variables are set for private registries 3. Confirm registry is online and accessible 4. Check namespace syntax is correct (@namespace/component)
Installation Failures: 1. Ensure valid components.json file 2. Confirm target directories exist 3. Check write permissions for component directories 4. Verify required dependencies are installed
Registry Schema
For publishing your own components:
Basic Registry Item
{
"name": "my-component",
"type": "registry:component",
"registryDependencies": ["button", "card"],
"dependencies": ["zod", "date-fns"],
"files": [
{
"path": "components/my-component.tsx",
"type": "registry:component",
"target": "components/my-component.tsx"
}
]
}Full Registry Item with Styling
{
"name": "my-component",
"type": "registry:component",
"registryDependencies": ["button", "card"],
"dependencies": ["zod", "date-fns"],
"devDependencies": ["@types/node"],
"tailwind": {
"config": {
"theme": {
"extend": {
"colors": {
"brand": "hsl(var(--brand))"
}
}
}
}
},
"cssVars": {
"light": {
"brand": "220 13% 10%"
},
"dark": {
"brand": "220 13% 90%"
}
},
"files": [
{
"path": "components/my-component.tsx",
"type": "registry:component"
}
],
"categories": ["ui"]
}Registry Types
| Type | Description |
|---|---|
registry:component | React component |
registry:hook | React hook |
registry:lib | Utility/library function |
registry:page | Page component (has target property for file-based routing) |
registry:block | Pre-built page/feature with multiple files |
registry:theme | Theme configuration |
Building Registry Files
# Generate registry JSON from registry.json
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest build
# Custom output directory
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest build --output ./public/registryCLI Commands Reference
Package Manager: Use your preferred package manager's executor:
npx(npm),bunx(bun),pnpm dlx(pnpm),yarn dlx(yarn)
init
Initialize configuration and dependencies:
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest init [options]
# Options:
-t, --template <template> # Template: next, next-monorepo
-b, --base-color <base-color> # Base color: neutral, gray, zinc, stone, slate
-y, --yes # Skip confirmation
-f, --force # Force overwrite
-c, --cwd <cwd> # Working directory
-s, --silent # Mute output
--src-dir # Use src directory
--css-variables # Use CSS variables (default: true)
--no-base-style # Don't install base styleadd
Add components to project:
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add [options] [components...]
# Options:
-y, --yes # Skip confirmation
-o, --overwrite # Overwrite existing files
-c, --cwd <cwd> # Working directory
-a, --all # Add all components
-p, --path <path> # Custom install path
-s, --silent # Mute outputview
View components before installing:
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view [item]
# View multiple
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view button card dialog
# View from namespaced registries
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view @acme/auth @v0/dashboardsearch
Search registries:
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search [options] <registries...>
# Examples
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn -q "button"
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn @v0 @acme
# Options:
-c, --cwd <cwd> # Working directory
-q, --query <query> # Search query
-l, --limit <number> # Max items per registry (default: 100)
-o, --offset <number> # Items to skip (default: 0)list
List items from registry (alias for search):
<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest list <registries...>Customization Best Practices
1. Customize the theme - Don't use defaults
/* Customize in globals.css */
:root {
--radius: 0.5rem; /* or 0 for sharp corners */
--primary: 220 13% 10%; /* custom primary */
}2. Extend components - Don't just copy-paste
- Add custom variants
- Modify animations
- Adjust spacing to match your aesthetic
3. Combine primitives creatively
- Layer components for unique effects
- Use Command for more than command palettes
- Use Sheet for custom navigation patterns
4. Follow the composition pattern
// Compose, don't configure
<Card>
<Card.Header>
<Card.Title>Header</Card.Title>
<Card.Description>Description</Card.Description>
</Card.Header>
<Card.Content>Content</Card.Content>
<Card.Footer>Footer</Card.Footer>
</Card>