frontend-design
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:
- Purpose: What problem does this interface solve? Who uses it?
- 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
- Constraints: Technical requirements (framework, performance, accessibility)
- Differentiation: What makes this UNFORGETTABLE?
CRITICAL: Choose a clear conceptual direction and execute it with precision.
Technology Stack Preferences
Component Libraries (Priority Order)
- shadcn/ui - First choice for React projects. Copy components, full customization.
- Radix UI - Accessible primitives when shadcn isn't available
- Headless UI - For Tailwind-based projects
- Custom CSS - When libraries aren't appropriate
Data Visualization
- Recharts - First choice for charts in React. Clean, composable, customizable.
- Tremor - Dashboard-ready charts with great defaults
- Victory - When Recharts doesn't fit
- D3.js - For complex, custom visualizations only
Styling
- Tailwind CSS - Utility-first, consistent spacing/colors
- CSS Variables - For theming and design tokens
- CSS Modules - When Tailwind isn't available
Animation
- Framer Motion - First choice for React animations
- CSS animations - For simple, performant effects
- 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.tsx
Anti-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
- Open Code: Full transparency, easy customization, AI-readable
- Composition: Common, composable interface across all components
- Distribution: Flat-file schema + CLI for easy installation
- Beautiful Defaults: Great design out-of-the-box, easily customizable
- 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
-
Customize the theme - Don't use defaults
:root { --radius: 0.5rem; /* or 0 for sharp corners */ --primary: 220 13% 10%; /* custom primary */ } -
Extend components - Add custom variants, modify animations, adjust spacing
-
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:
-
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> -
Remove visual clutter
- Hide axis lines when not needed
- Use subtle grid lines or none
- Custom tooltips that match your design
-
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:
- Explain the aesthetic direction (2-3 sentences)
- List key design decisions (typography, colors, key components)
- 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)
More from duyet/claude-plugins
react-nextjs-patterns
React and Next.js implementation patterns for performance and maintainability. Use when building frontend components, pages, and applications with React ecosystem.
135backend-api-patterns
Backend and API implementation patterns for scalability, security, and maintainability. Use when building APIs, services, and backend infrastructure.
40quality-gates
Systematic quality verification procedures for code review and delivery. Use when validating completed work, conducting code reviews, or ensuring production readiness.
36gemini-prompting
Prompt engineering guidance for Gemini (Google) model. Use when crafting prompts for Gemini to leverage system instructions, multimodal capabilities, ultra-long context, and strong reasoning features.
26orchestration
Orchestrate complex work through parallel agent coordination. Decompose requests into task graphs, spawn background workers, and synthesize results elegantly. Use for multi-component features, large investigations, or any work benefiting from parallelization.
19engineering-discipline
Core engineering principles for sustainable, maintainable code. No shortcuts, no hacks. Quality gates before completion.
19