---
name: design
description: Auto-activates when user mentions UI design, design systems, or component design. Expert in design principles, accessibility, and component architecture.
category: design
---
# UI/UX Design Guidelines
## Core Principles
1. **User-Centered Design** - Always design for the user's needs, not your preferences
2. **Consistency** - Maintain consistent patterns across the entire interface
3. **Accessibility First** - Design for all users, including those with disabilities
4. **Progressive Disclosure** - Show only what's needed, when it's needed
5. **Feedback & Affordance** - Make interactions clear and provide immediate feedback
## Design System Foundations
### Design Tokens
Use design tokens for all visual properties to ensure consistency and enable theming:
```css
/* ✅ Good: Use design tokens */
:root {
/* Colors */
--color-primary: #0066ff;
--color-secondary: #6b7280;
--color-success: #10b981;
--color-error: #ef4444;
--color-warning: #f59e0b;
/* Spacing (8px grid) */
--space-xs: 0.25rem; /* 4px */
--space-sm: 0.5rem; /* 8px */
--space-md: 1rem; /* 16px */
--space-lg: 1.5rem; /* 24px */
--space-xl: 2rem; /* 32px */
--space-2xl: 3rem; /* 48px */
/* Typography */
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: "SF Mono", Monaco, "Cascadia Code", monospace;
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
/* Border radius */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
}
```
### ❌ Bad: Hardcoded values
```css
.button {
padding: 12px 20px; /* Should use design tokens */
background: #0066ff; /* Should use --color-primary */
font-size: 14px; /* Should use --text-sm */
}
```
## Component Design Patterns
### Buttons
```tsx
// ✅ Good: Comprehensive button with states
interface ButtonProps {
variant: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
loading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
children: React.ReactNode;
onClick?: () => void;
}
export function Button({
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
leftIcon,
rightIcon,
children,
onClick,
...props
}: ButtonProps) {
return (
{loading && }
{!loading && leftIcon}
{children}
{!loading && rightIcon}
);
}
```
### Form Inputs
```tsx
// ✅ Good: Accessible form input with error states
interface InputProps {
label: string;
id: string;
type?: string;
error?: string;
hint?: string;
required?: boolean;
disabled?: boolean;
}
export function Input({
label,
id,
type = 'text',
error,
hint,
required = false,
disabled = false,
...props
}: InputProps) {
return (
{label}
{required && * }
{hint && !error && (
{hint}
)}
{error && (
{error}
)}
);
}
```
## Accessibility (a11y) Requirements
### Semantic HTML
```tsx
// ✅ Good: Semantic HTML
Article Title
January 15, 2025
Article content...
// ❌ Bad: Non-semantic divs
```
### ARIA Labels & Roles
```tsx
// ✅ Good: Proper ARIA usage
{message}
// Screen reader only text
Loading...
```
### Keyboard Navigation
```tsx
// ✅ Good: Full keyboard support
function Dropdown() {
const handleKeyDown = (e: React.KeyboardEvent) => {
switch (e.key) {
case 'Escape':
close();
break;
case 'ArrowDown':
focusNextItem();
break;
case 'ArrowUp':
focusPreviousItem();
break;
case 'Enter':
case ' ':
selectItem();
break;
}
};
return (
{/* Items */}
);
}
```
### Color Contrast (WCAG AA)
- Normal text: 4.5:1 minimum
- Large text (18pt+): 3:1 minimum
- UI components & graphics: 3:1 minimum
```tsx
// ✅ Good: Sufficient contrast
Primary text with high contrast
// ❌ Bad: Insufficient contrast
Low contrast text (hard to read)
```
## Layout & Spacing
### 8px Grid System
Always use multiples of 8 for spacing and dimensions:
```tsx
// ✅ Good: 8px grid
{/* 16px, 8px */}
{/* 48px, 128px */}
// ❌ Bad: Random values
```
### Responsive Breakpoints (Mobile-First)
```tsx
// ✅ Good: Mobile-first responsive
```
### Whitespace & Hierarchy
```tsx
// ✅ Good: Clear visual hierarchy
Section Title
Section description
{/* Related content grouped together */}
```
## Typography
### Type Scale
```tsx
// ✅ Good: Consistent type scale
Main Heading
Section Heading
Subsection
Body text
Helper text
```
### Line Height & Letter Spacing
```css
/* ✅ Good: Readable typography */
.text-display {
font-size: 3rem;
line-height: 1.2; /* Tight for headings */
letter-spacing: -0.02em;
}
.text-body {
font-size: 1rem;
line-height: 1.6; /* Relaxed for body text */
letter-spacing: 0;
}
```
## Color System
### Semantic Colors
```tsx
// ✅ Good: Semantic color usage
```
### Dark Mode
```tsx
// ✅ Good: Always include dark mode
```
## User Feedback & States
### Loading States
```tsx
// ✅ Good: Clear loading indication
{isLoading ? (
Loading data...
) : (
)}
```
### Empty States
```tsx
// ✅ Good: Helpful empty state
function EmptyState() {
return (
No projects
Get started by creating a new project.
New Project
);
}
```
### Error States
```tsx
// ✅ Good: Actionable error message
{error && (
Error loading data
{error.message}
Try again
)}
```
## Micro-interactions
### Hover & Focus States
```tsx
// ✅ Good: Clear interactive states
Click me
```
### Animations (Subtle & Purposeful)
```tsx
// ✅ Good: Smooth entrance animation
Content appears smoothly
// Respect prefers-reduced-motion
```
## Mobile-First Considerations
### Touch Targets
```tsx
// ✅ Good: Minimum 44x44px touch targets
Tap
// Increase tap area without visual size
```
### Safe Areas (iOS/Android)
```css
/* ✅ Good: Respect device safe areas */
.container {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
}
```
## Design-to-Code Workflow
When converting designs to code:
1. **Analyze the Design**
- Identify reusable components
- Note color palette and typography
- Map out spacing system
2. **Build from Atoms to Organisms**
- Start with design tokens
- Create base components (buttons, inputs)
- Compose into larger patterns
- Build full layouts
3. **Ensure Responsiveness**
- Mobile-first approach
- Test at all breakpoints
- Progressive enhancement
4. **Add Interactivity**
- Hover/focus states
- Loading/error states
- Smooth transitions
- Keyboard navigation
5. **Accessibility Audit**
- Semantic HTML
- ARIA labels
- Color contrast
- Keyboard navigation
- Screen reader testing
## Common Patterns
### Card Component
```tsx
// ✅ Good: Flexible card component
Card Title
Card description goes here
Main content
Cancel
Save
```
### Modal/Dialog
```tsx
// ✅ Good: Accessible modal
Dialog Title
Dialog content goes here
Cancel
Confirm
```
## Advanced ARIA Patterns
### ✅ Good: Accessible Dialog/Modal
```tsx
import * as React from 'react';
import * as Dialog from '@radix-ui/react-dialog';
function AccessibleModal() {
return (
Open Dialog
Delete Account
This action cannot be undone. This will permanently delete your account.
Cancel
Delete
);
}
```
### ✅ Good: Accessible Dropdown Menu
```tsx
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
function AccessibleDropdown() {
return (
Edit
⌘E
Duplicate
⌘D
Delete
⌘⌫
);
}
```
### ✅ Good: Accessible Tabs Pattern
```tsx
import * as Tabs from '@radix-ui/react-tabs';
function AccessibleTabs() {
return (
Profile
Settings
Billing
Profile
Manage your profile settings here.
Settings
Configure your application settings.
Billing
Manage your billing information.
);
}
```
### ✅ Good: Accessible Accordion
```tsx
import * as Accordion from '@radix-ui/react-accordion';
function AccessibleAccordion() {
return (
What is accessibility?
Accessibility ensures that people with disabilities can perceive, understand, navigate, and interact with websites and tools.
Why is WCAG important?
WCAG (Web Content Accessibility Guidelines) provides a standard for making web content accessible to all users, including those with disabilities.
);
}
```
### ✅ Good: Toast Notifications with Live Regions
```tsx
import * as Toast from '@radix-ui/react-toast';
function ToastNotifications() {
const [open, setOpen] = React.useState(false);
return (
setOpen(true)}>Show notification
Update available
A new version of the app is ready to install.
Install
);
}
```
## Complete Keyboard Navigation Guide
### ✅ Good: Focus Management in Modals
```tsx
import { useEffect, useRef } from 'react';
function FocusTrappedModal({ isOpen, onClose, children }) {
const modalRef = useRef
(null);
const previousFocusRef = useRef(null);
useEffect(() => {
if (isOpen) {
// Store currently focused element
previousFocusRef.current = document.activeElement as HTMLElement;
// Focus first focusable element in modal
const firstFocusable = modalRef.current?.querySelector(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
) as HTMLElement;
firstFocusable?.focus();
// Trap focus within modal
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return;
const focusableElements = Array.from(
modalRef.current?.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
) || []
) as HTMLElement[];
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
// Restore focus when modal closes
previousFocusRef.current?.focus();
};
}
}, [isOpen]);
if (!isOpen) return null;
return (
{children}
);
}
```
### ✅ Good: Skip Links
```tsx
// At the top of your app
function App() {
return (
<>
Skip to main content
{/* Main content */}
>
);
}
```
### ✅ Good: Keyboard Shortcuts
```tsx
import { useEffect } from 'react';
function useKeyboardShortcut(
key: string,
callback: () => void,
modifiers: { ctrl?: boolean; shift?: boolean; alt?: boolean } = {}
) {
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
const matchesModifiers =
(modifiers.ctrl ? e.ctrlKey || e.metaKey : !e.ctrlKey && !e.metaKey) &&
(modifiers.shift ? e.shiftKey : !e.shiftKey) &&
(modifiers.alt ? e.altKey : !e.altKey);
if (e.key === key && matchesModifiers) {
e.preventDefault();
callback();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [key, callback, modifiers]);
}
// Usage
function Editor() {
useKeyboardShortcut('s', handleSave, { ctrl: true });
useKeyboardShortcut('k', openSearch, { ctrl: true });
useKeyboardShortcut('/', focusSearch);
return ...
;
}
```
## Responsive Design Complete Guide
### ✅ Good: Mobile-First Breakpoint Strategy
```tsx
// tailwind.config.js
module.exports = {
theme: {
screens: {
'sm': '640px', // Small devices (phones, 640px and up)
'md': '768px', // Medium devices (tablets, 768px and up)
'lg': '1024px', // Large devices (desktops, 1024px and up)
'xl': '1280px', // Extra large devices (large desktops, 1280px and up)
'2xl': '1536px', // 2X large devices (larger desktops, 1536px and up)
}
}
};
// Mobile-first component
function ResponsiveGrid() {
return (
{items.map(item => )}
);
}
```
### ✅ Good: Container Queries (Modern Approach)
```tsx
// Use container queries for truly responsive components
function ProductCard() {
return (
);
}
```
### ✅ Good: Responsive Typography
```tsx
// Fluid typography using clamp()
const styles = {
heading: {
fontSize: 'clamp(1.5rem, 5vw, 3rem)', // Min 24px, scales with viewport, max 48px
lineHeight: '1.2',
},
body: {
fontSize: 'clamp(1rem, 2.5vw, 1.125rem)', // Min 16px, max 18px
lineHeight: '1.6',
}
};
// Or with Tailwind
Responsive Heading
```
### ✅ Good: Touch-Friendly Interfaces
```tsx
// Minimum touch target: 44x44px (iOS), 48x48px (Android)
function TouchFriendlyButton() {
return (
Tap Me
);
}
// Increase tap area without changing visual size
function IconButton() {
return (
{/* Extend tap area beyond visual bounds */}
);
}
```
### ✅ Good: iOS/Android Safe Areas
```css
/* Respect device safe areas (notches, rounded corners) */
.app-container {
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
/* Fixed header accounting for safe areas */
.fixed-header {
position: fixed;
top: 0;
left: 0;
right: 0;
padding-top: calc(1rem + env(safe-area-inset-top));
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
```
## Design Tokens & Design Systems
### ✅ Good: Comprehensive Design Token System
```typescript
// design-tokens.ts
export const tokens = {
colors: {
// Brand colors
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
900: '#1e3a8a',
},
// Semantic colors
success: '#10b981',
warning: '#f59e0b',
error: '#ef4444',
info: '#3b82f6',
// Neutrals
gray: {
50: '#f9fafb',
100: '#f3f4f6',
500: '#6b7280',
900: '#111827',
}
},
spacing: {
0: '0',
1: '0.25rem', // 4px
2: '0.5rem', // 8px
3: '0.75rem', // 12px
4: '1rem', // 16px
6: '1.5rem', // 24px
8: '2rem', // 32px
12: '3rem', // 48px
16: '4rem', // 64px
},
typography: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }], // 12px
sm: ['0.875rem', { lineHeight: '1.25rem' }], // 14px
base: ['1rem', { lineHeight: '1.5rem' }], // 16px
lg: ['1.125rem', { lineHeight: '1.75rem' }], // 18px
xl: ['1.25rem', { lineHeight: '1.75rem' }], // 20px
'2xl': ['1.5rem', { lineHeight: '2rem' }], // 24px
},
fontWeight: {
normal: '400',
medium: '500',
semibold: '600',
bold: '700',
}
},
borderRadius: {
none: '0',
sm: '0.125rem', // 2px
md: '0.375rem', // 6px
lg: '0.5rem', // 8px
xl: '0.75rem', // 12px
full: '9999px',
},
shadows: {
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1)',
},
animation: {
duration: {
fast: '150ms',
base: '200ms',
slow: '300ms',
},
easing: {
linear: 'linear',
in: 'cubic-bezier(0.4, 0, 1, 1)',
out: 'cubic-bezier(0, 0, 0.2, 1)',
inOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
}
},
zIndex: {
dropdown: 1000,
sticky: 1020,
modal: 1040,
popover: 1050,
toast: 1060,
}
} as const;
```
### ✅ Good: Component Variant System
```tsx
// Using class-variance-authority (CVA)
import { cva, type VariantProps } from 'class-variance-authority';
const button = cva(
// Base styles
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
ghost: 'hover:bg-gray-100',
danger: 'bg-red-600 text-white hover:bg-red-700',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg',
},
disabled: {
true: 'opacity-50 cursor-not-allowed pointer-events-none',
}
},
defaultVariants: {
variant: 'primary',
size: 'md',
}
}
);
type ButtonProps = VariantProps &
React.ButtonHTMLAttributes;
export function Button({ variant, size, disabled, className, ...props }: ButtonProps) {
return (
);
}
```
## Liquid Glass Effects (Advanced)
Apple's Liquid Glass UI from WWDC 2025 uses physics-based refraction for premium glass effects.
### Core Physics
**Refraction** = Light bending through materials (Snell's Law)
- **Convex surfaces** (dome) - Push rays inward, keep content inside
- **Concave surfaces** (bowl) - Push rays outward, divergence
- **Squircle** (Apple's choice) - Smoother transitions, softer refraction edges
### ✅ Good: Basic Glass Panel (Cross-Browser)
```css
.glass-panel {
position: relative;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px) saturate(180%);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.6);
}
/* Specular highlight */
.glass-panel::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.4) 0%,
transparent 50%
);
pointer-events: none;
}
```
### ✅ Good: SVG Displacement Maps (Chrome Only)
```html
```
```css
.liquid-glass {
backdrop-filter: blur(3px) url(#glass-distortion);
overflow: hidden;
}
/* Layer structure */
.liquid-glass-filter { z-index: 0; filter: url(#glass-distortion); }
.liquid-glass-tint { z-index: 1; background: rgba(255, 255, 255, 0.25); }
.liquid-glass-specular { z-index: 2; box-shadow: inset 2px 2px 1px rgba(255, 255, 255, 0.5); }
.liquid-glass-content { z-index: 3; position: relative; }
```
### ✅ Good: Interactive Glass with Mouse Tracking
```tsx
function InteractiveGlass() {
const handleMouseMove = (e: React.MouseEvent) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const specular = e.currentTarget.querySelector('.glass-specular') as HTMLElement;
if (specular) {
specular.style.background = `radial-gradient(
circle at ${x}px ${y}px,
rgba(255, 255, 255, 0.15) 0%,
rgba(255, 255, 255, 0.05) 30%,
rgba(255, 255, 255, 0) 60%
)`;
}
};
return (
);
}
```
### Design Parameters
- **Bezel Width**: 10-30px (edge refraction intensity)
- **Glass Thickness**: 50-150px (displacement magnitude)
- **Surface Shape**: Squircle for Apple-like smoothness
- **Specular Opacity**: 0.2-0.5 (highlight intensity)
- **Blur Level**: 3-20px (background blur strength)
### Browser Support
| Feature | Chrome | Safari | Firefox |
|---------|--------|--------|---------|
| `backdrop-filter` | ✅ | ✅ | ✅ |
| SVG as `backdrop-filter` | ✅ | ❌ | ❌ |
| Basic glass | ✅ | ✅ | ✅ |
| Advanced refraction | ✅ | ❌ | ❌ |
**Strategy**: Use basic glass for cross-browser, advanced SVG refraction as progressive enhancement for Chrome.
### Use Cases
**✅ When to use:**
- Premium UI (cards, panels, modals)
- Hero sections with depth
- Navigation bars with transparency
- Music/media player controls
**❌ When to avoid:**
- Text-heavy content (readability)
- High-contrast backgrounds (effect less visible)
- Mobile (performance concerns)
- Accessibility-critical UI
### Performance
✅ **Use CSS transforms** (hardware accelerated)
✅ **Limit blur radius** (smaller = faster)
✅ **Use `will-change`** for animations
❌ **Don't nest glass effects** (compounds cost)
❌ **Don't animate displacement maps** (pre-calculate)
### References
- [Liquid Glass CSS/SVG](https://kube.io/blog/liquid-glass-css-svg/) - Complete physics guide
- [Apple WWDC 2025](https://www.youtube.com/watch?v=jGztGfRujSE) - Official introduction
- [Glassmorphism UI](https://liquidglassui.org/) - Library & components
---
## Accessibility Testing Tools
### ✅ Good: Automated Testing with axe-core
```typescript
// __tests__/accessibility.test.tsx
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
describe('Accessibility', () => {
it('should not have any accessibility violations', async () => {
const { container } = render( );
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
```
### ✅ Good: Manual Testing Checklist
```markdown
## Accessibility Testing Checklist
### Keyboard Navigation
- [ ] All interactive elements are keyboard accessible
- [ ] Focus is visible on all focusable elements
- [ ] Tab order is logical
- [ ] No keyboard traps
- [ ] Skip links work correctly
### Screen Reader
- [ ] All images have alt text
- [ ] ARIA labels are present where needed
- [ ] Form inputs have associated labels
- [ ] Headings follow proper hierarchy (h1 → h2 → h3)
- [ ] Live regions announce dynamic content
### Visual
- [ ] Color contrast meets WCAG AA (4.5:1 for normal text)
- [ ] Content is readable when zoomed to 200%
- [ ] No information conveyed by color alone
- [ ] Focus indicators are visible
### Forms
- [ ] All form fields have labels
- [ ] Error messages are descriptive
- [ ] Required fields are indicated
- [ ] Validation errors are announced to screen readers
```
**ALWAYS follow these design principles and patterns to create accessible, consistent, and user-friendly interfaces. Test with real screen readers (NVDA, JAWS, VoiceOver) and keyboard-only navigation to ensure true accessibility. For premium effects, consider liquid glass techniques with proper cross-browser fallbacks.**