design-lab
Interactive design exploration workflow: conduct interviews, generate variants, and refine UI designs through feedback.
Install
npx skills add https://github.com/0xdesign/design-plugin --skill design-labDesign Principles Reference
This document contains curated best practices from world-class designers and design systems. Reference these principles when generating design variations.
Part 1: UX Foundations
Jakob Nielsen's 10 Usability Heuristics
- Visibility of system status - Always keep users informed through appropriate feedback within reasonable time
- Match between system and real world - Use familiar language, concepts, and conventions
- User control and freedom - Provide clear "emergency exits" (undo, cancel, back)
- Consistency and standards - Follow platform conventions; same words mean same things
- Error prevention - Eliminate error-prone conditions or ask for confirmation
- Recognition over recall - Minimize memory load; make options visible
- Flexibility and efficiency - Provide accelerators for expert users (shortcuts, defaults)
- Aesthetic and minimalist design - Remove irrelevant information; every element competes
- Help users recover from errors - Plain language errors with constructive solutions
- Help and documentation - Provide concise, task-focused help when needed
Don Norman's Design Principles
- Affordances - Design elements should suggest their usage
- Signifiers - Visual cues that indicate where actions should happen
- Mapping - Controls should relate spatially to their effects
- Feedback - Every action needs a perceivable response
- Conceptual model - Users should understand how the system works
Cognitive Load Principles
- Limit choices - 5-7 items max in navigation; 3-4 options in decisions
- Progressive disclosure - Show only what's needed at each step
- Chunking - Group related items; break long forms into steps
- Visual hierarchy - Guide attention with size, color, contrast, position
- Reduce cognitive friction - Minimize decisions, clicks, and reading
URL & State Principles
- URL state reflection - Important UI state (filters, tabs, pagination) should be in the URL
- Shareable links - Users should be able to share/bookmark the current view
- Browser navigation - Back/forward buttons should work as expected
Destructive Actions
- Confirmation required - Delete, remove, and irreversible actions need explicit confirmation
- Clear consequences - State exactly what will happen ("This will permanently delete 5 files")
- Recovery path - Prefer soft delete with undo over immediate permanent deletion
- Visual distinction - Destructive buttons use warning colors (red) and distinct styling
Part 2: Visual Design Systems
Typography (from iA, Stripe, Linear)
Hierarchy:
Best practices:
- Max 60-75 characters per line for readability
- Line height: 1.4-1.6 for body text, 1.2-1.3 for headings
- Use weight contrast (400 vs 600) more than size contrast
- Limit to 2 font families maximum
- System fonts for performance:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif
Typographic details:
- Use proper ellipsis
…not...(three dots) - Use curly quotes
""not straight quotes" - Non-breaking spaces for values:
10 MB,5 items(use or\u00A0) font-variant-numeric: tabular-numsfor numbers in tables, counters, pricestext-wrap: balancefor headings (prevents orphans/widows)text-wrap: prettyfor body text (better line breaks)
Spacing System (8px grid)
Spacing principles:
- Related items closer together (Gestalt proximity)
- Consistent internal padding (all sides equal, or vertical > horizontal)
- White space is not wasted space—it creates focus
- Touch targets minimum 44x44px (Apple HIG)
Color (from Stripe, Linear, Vercel)
Neutral foundation:
Accent usage:
- Primary action: single brand color, used sparingly
- Interactive elements: consistent color for all clickable items
- Semantic colors: red (error), green (success), yellow (warning), blue (info)
- Hover states: 10% darker or add subtle background
- Focus states: 2px ring with offset, high contrast
Color principles:
- WCAG AA minimum: 4.5:1 for text, 3:1 for UI elements
- One primary accent color; avoid rainbow interfaces
- Use opacity for secondary states (hover, disabled)
- Dark mode: don't just invert—reduce contrast, use darker surfaces
Dark mode setup:
Content Handling
Text truncation:
Flex children with text:
Empty states:
- Always design the empty state—it's the first thing users see
- Include helpful message + primary action
- Use illustration or icon to add visual interest
Images:
Border Radius (from modern SaaS)
Principles:
- Consistency: pick 2-3 radius values and stick to them
- Nested elements: inner radius = outer radius - padding
- Sharp corners feel technical/precise; round feels friendly/approachable
Shadows & Elevation (from Material, Linear)
Principles:
- Shadows should feel like natural light (top-down, slight offset)
- Dark mode: use lighter surface colors instead of shadows
- Combine with subtle border for definition
- Interactive elements can elevate on hover
Part 3: Component Patterns
Buttons (from Stripe, Linear)
Hierarchy:
- Primary - One per view, main action, filled with brand color
- Secondary - Supporting actions, outlined or ghost style
- Tertiary - Low-emphasis actions, text-only with hover state
- Destructive - Delete/remove actions, red with confirmation
States:
- Default → Hover (+shadow or darken) → Active (scale 0.97) → Disabled (50% opacity)
- Loading: replace text with spinner, maintain width
- Min width: 80px; min height: 36px (touch-friendly: 44px)
Best practices:
- Specific labels: "Save API Key" not "Continue" or "Submit"
- Verb + noun labels: "Create project" not "Create"
- Sentence case, not ALL CAPS
- Icon left of text (or icon-only with tooltip)
- Primary button right-aligned in forms/dialogs
- Icon buttons require
aria-label
Active state feedback:
Forms (from Airbnb, Stripe, Vercel)
Input anatomy:
Autocomplete attributes (required):
Input types and modes:
Disable spellcheck where inappropriate:
Anti-patterns to avoid:
Best practices:
- Labels above inputs (not inside—accessibility)
- Placeholder ≠ label; use for format hints only, end with
... - Inline validation on blur, not on every keystroke
- Error messages: specific and actionable ("Email must include @")
- Focus first error field after form submission fails
- Success state: checkmark icon, green border (brief)
- Required fields: mark optional ones instead of required
- Single column forms outperform multi-column
Unsaved changes warning:
Cards (from Material, Apple)
Anatomy:
Best practices:
- Entire card clickable for primary action
- Consistent padding (16-24px)
- Image aspect ratios: 16:9, 4:3, 1:1 (be consistent)
- Limit to 2 actions max; overflow to menu
- Hover: subtle lift (translateY -2px + shadow increase)
Tables (from Linear, Notion)
Best practices:
- Left-align text, right-align numbers
- Use
tabular-numsfor numeric columns (consistent width digits) - Zebra striping OR row hover, not both
- Sticky header on scroll
- Sortable columns: show current sort indicator
- Actions: row hover reveals action buttons (or kebab menu)
- Empty state: helpful message + action
- Pagination vs infinite scroll: pagination for data accuracy, infinite for browsing
- Min row height: 48px for touch; 40px for dense
- Virtualize tables with >50 rows
Navigation (from Apple HIG, Material)
Patterns by scale:
- 2-5 items: Tab bar / horizontal tabs
- 5-10 items: Side navigation (collapsible)
- 10+ items: Side nav with sections/groups
Best practices:
- Current location always visible
- Breadcrumbs for deep hierarchy (not for flat structures)
- Mobile: bottom nav for primary actions (thumb-friendly)
- Icons + labels together; icon-only needs tooltip
- Consistent order across pages
Part 4: Interaction Design
Feedback Patterns (from Dan Saffer's Microinteractions)
Every action needs feedback:
- Immediate - Button press visual (scale, color change)
- Progress - Loading states for anything >1s
- Completion - Success confirmation (toast, checkmark, animation)
- Failure - Clear error with recovery path
Loading states:
- 0-100ms: No indicator needed
- 100-300ms: Subtle change (opacity, skeleton)
- 300ms-1s: Spinner or progress bar
- 1s+: Skeleton screens + progress indication
- 10s+: Background processing with notification
State Handling
Every component needs these states:
Touch & Pointer Interactions
Faster tap response:
Contain scroll in modals:
Touch targets:
- Minimum 44x44px for all interactive elements (Apple HIG)
- Provide adequate spacing between targets (8px minimum)
Hover states for pointer devices only:
Tap highlight:
Optimistic Updates (from Linear, Notion)
- Update UI immediately, sync in background
- Show subtle "Saving..." indicator
- On failure: revert UI + show error toast with retry
- Best for: toggles, reordering, text edits
- Avoid for: destructive actions, payments
Progressive Disclosure
Reveal complexity gradually:
- Show essential options first
- "Advanced" or "More options" for power features
- Inline expansion over page navigation
- Tooltips for supplementary information
- Context menus for secondary actions
Inferring Intent
Anticipate user actions before they happen:
Proximity-based preloading:
Smart defaults:
- Pre-fill forms with likely values
- Remember user's last selection
- Use geolocation for location fields
- Default date pickers to sensible dates (today, tomorrow)
Interaction Metaphors
Physical analogies users already understand:
Consistency requirement:
Once you establish a gesture metaphor, use it consistently:
Honor platform conventions:
- iOS: Swipe from left edge = back navigation
- Android: Back button/gesture = return to previous screen
- Desktop: Right-click = context menu
Ergonomic Interactions
Expand hit areas with pseudo-elements:
Bidirectional scroll support:
Thumb-friendly mobile zones:
Contained Gestures
Prevent gesture conflicts with parent elements:
Pointer capture for drag operations:
Drag threshold detection:
Gesture state machine:
Part 5: Motion & Animation
The Frequency Principle
Animation frequency should match usage frequency:
Example: A "send message" button used constantly → instant. An "export report" button used weekly → can animate.
Easing Blueprint
Ease-out family (most common):
Use for entrances, user-initiated actions, and most UI transitions.
Ease-in-out family:
Use for on-screen movement (element moving from point A to point B).
Easing decision flowchart:
Timing Guidelines
Important: Exit animations should be 20-30% faster than entrances.
Animation Patterns
Entrances:
- Fade in + slide up (8-16px)
- Scale from 0.95 to 1 + fade (never from 0)
- Stagger children by 30-50ms
Exits:
- Fade out (faster than entrance)
- Scale to 0.95 + fade
- Slide in direction of dismissal
Transform origin:
Always set transform-origin toward the trigger element:
Hover flicker prevention:
Sequential tooltips:
After the first tooltip in a series, skip animation for subsequent ones:
Spring Physics
When to use springs:
- Drag and drop interactions
- Gesture-based animations
- Interruptible motion (user can grab mid-animation)
- Physics-based feel (natural, organic)
Spring parameters:
Critical principle: Never reuse spring values
Each interaction should have its own tuned spring. A dropdown menu spring differs from a drag-to-dismiss spring.
Damping for rubber band effects:
iOS-style projection (momentum scrolling):
Framer Motion spring shorthand:
Motion Choreography
Blur overlapping layers:
When animated elements cross paths, they create visual noise. Add subtle blur:
Stagger animation delays:
Double exit stiffness:
Exit animations should feel quicker. Double the spring stiffness:
Crossfade icons (not swap):
When changing icons, don't just swap. Scale down + blur out the old, scale up + blur in the new:
Morph surfaces with overflow: hidden:
When morphing between shapes, prevent content from spilling:
High-Frequency Actions
No fade-in for menus:
Menus triggered frequently should appear instantly, but can fade out:
Skip animation between rapid data updates:
Keyboard interactions often need no animation:
Gesture Lifecycle
Three phases of gesture handling:
Use jump() for continuous updates, set() for animated snap:
useTransform for derived values:
Gesture state tracking:
Animation Performance
Only animate compositor properties:
Never use transition: all:
Fix transform shakiness:
CSS vs JavaScript animations:
Reduced Motion
Every animation needs a reduced motion alternative:
Framer Motion hook:
What reduced motion should do:
- Remove parallax effects
- Stop auto-playing videos/carousels
- Replace slide/scale with fade or instant
- Keep essential feedback (success checkmarks can still appear, just not animated)
Part 6: Accessibility Essentials
WCAG Quick Reference
Perceivable:
- Color contrast: 4.5:1 text, 3:1 UI components
- Don't rely on color alone (add icons, patterns)
- Text resizable to 200% without loss
- Captions for video; transcripts for audio
Operable:
- All functionality via keyboard
- No keyboard traps
- Skip links for repeated content
- Touch targets: 44x44px minimum
Understandable:
- Consistent navigation
- Identify input errors clearly
- Labels and instructions for forms
Robust:
- Semantic HTML elements
- ARIA only when HTML isn't enough
- Tested with screen readers
Focus Management
Use :focus-visible over :focus:
Compound controls:
Keyboard Navigation
All interactive elements must be keyboard-operable:
Keyboard patterns:
- Tab order must match visual order
- Enter/Space activate buttons and links
- Escape closes dialogs and dropdowns
- Arrow keys navigate within components (tabs, menus)
ARIA Patterns
Icon buttons require aria-label:
Form controls require labels:
Live regions for async updates:
Semantic HTML before ARIA:
Common ARIA patterns:
Part 7: Performance Patterns
Virtualization
Large lists require virtualization:
CSS-based virtualization:
Layout Thrashing
Avoid layout reads in render:
Properties that trigger layout:
offsetHeight,offsetWidth,offsetTop,offsetLeftgetBoundingClientRect()scrollHeight,scrollWidth,scrollTop,scrollLeftgetComputedStyle()
Resource Loading
Preconnect to CDN domains:
Preload critical fonts:
Image loading strategy:
Part 8: Content & Copy
Writing Style
Active voice over passive:
Title Case for headings and buttons:
Use numerals:
Labels & Messages
Specific labels over generic:
Error messages include fix/next step:
Internationalization
Use Intl APIs for formatting:
Part 9: Anti-Patterns Checklist
Flag these patterns during design review:
Accessibility Violations
-
user-scalable=noormaximum-scale=1in viewport meta -
<div onClick>instead of<button>for interactive elements - Form inputs without associated labels
- Icon buttons without
aria-label -
outline: nonewithout focus replacement
Performance Issues
-
transition: all(animates layout properties) - Images without explicit
widthandheight - Large arrays (>50 items) rendered without virtualization
- Layout reads (
getBoundingClientRect) in render cycle
UX Problems
-
onPastewithpreventDefault()(blocks paste) - Hardcoded date/number formats (not using Intl)
- Placeholder used as label
- Validation on every keystroke
- No empty state designed
Mobile Issues
- Touch targets smaller than 44x44px
- No
touch-action: manipulationon buttons - Hover effects without
@media (hover: hover)query
Interface Robustness Checklist
Test every interactive component against these stress conditions:
Rapid User Input:
- Scroll fast — does it break or show visual glitches?
- Spam click — does it trigger multiple actions or crash?
- Resize window rapidly — does layout break or cause errors?
- Type very fast in inputs — does it lag or lose characters?
Animation Interruption:
- Interrupt animations mid-way — does it recover gracefully?
- Close modal while opening — does it handle state correctly?
- Navigate away during transition — does it clean up properly?
- Trigger multiple animations simultaneously — do they conflict?
Network Conditions:
- Test with slow network (3G throttling) — does it show loading states?
- Test with offline mode — does it fail gracefully?
- Test with request timeout — does it retry or show error?
Input Methods:
- Test with keyboard only — is everything accessible?
- Test with screen reader — are states announced?
- Test with touch device — are hit areas adequate?
- Test with trackpad gestures — do scroll/swipe work correctly?
State Combinations:
- Test all combinations of loading + error + empty states
- Test disabled state during async operations
- Test hover + focus + active simultaneously
- Test with maximum and minimum content
Memory & Performance:
- Run for extended period — does memory grow unbounded?
- Test with large datasets — does it virtualize or paginate?
- Monitor for memory leaks in animations and observers
- Check for event listener cleanup on unmount
Part 10: Design System References
Study These Systems
For Clarity & Precision:
- Linear - Information density done right
- Stripe - Trust through craft
- Vercel - Developer-focused simplicity
For Warmth & Approachability:
For Data & Density:
- Bloomberg Terminal - Maximum information
- Figma - Tool-like precision
- GitHub - Code-centric clarity
For Motion & Delight:
When Generating Variants
Reference specific aspects:
- "Use Linear's density approach"
- "Stripe's button hierarchy"
- "Airbnb's card layout"
- "Notion's toggle interaction"
- "Vercel's dark mode palette"
Part 11: Code Patterns Library
Practical patterns for implementing advanced interactions.
useMotionValue vs useState
Performance difference:
Use useMotionValue for:
- Continuous animation values (position, scale, opacity)
- Gesture-driven values (drag position)
- Any value that changes at 60fps
Use useState for:
- Discrete states (open/closed, active tab)
- Values that trigger layout changes
useSpring: jump() vs set()
Grid Stacking for Overlapping Elements
Stack elements using CSS Grid (no absolute positioning):
Benefits over position: absolute:
- Children contribute to parent size
- Natural document flow
- Better for responsive layouts
Native Scroll vs Wheel Events
Prefer native scroll over wheel event listeners:
When you need scroll position reactively:
clip-path for Animated Resizing
Animate size without layout shifts:
Reveal patterns:
Scroll Fading (Blur Fade Effect)
Fade content at scroll edges:
overflow: clip vs hidden
Use clip when you don't need scroll:
When to use each:
hidden- Need scrollable overflow (JS can scroll it)clip- Just want to hide overflow, no scroll needed (better perf)
Re-mount with React Key for CSS Keyframes
Replay CSS animations by changing key:
Smart Image Preloading
Preload images before they're needed:
layoutId for Shared Element Transitions
Morph elements between views:
Debounced Resize Observer
Prevent excessive callbacks during resize:
Quick Decision Framework
When unsure, ask:
- Is it clear? → User knows what to do and what happened
- Is it fast? → Minimum steps, appropriate feedback
- Is it consistent? → Matches patterns elsewhere in the app
- Is it accessible? → Keyboard, screen reader, color contrast
- Is it calm? → No unnecessary motion, color, or elements
- Is it specific? → Labels describe exactly what will happen
- Is it recoverable? → User can undo or go back