UX guidelines¶
A catalog of common UX issues with do/don't pairs. Use as a review checklist before sign-off and as a learning index for new designers.
AI Interaction¶
🔴 Disclaimer (All)¶
Users need to know they talk to AI
Do: Clearly label AI generated content Don't: Present AI as human
🟡 Streaming (All)¶
Waiting for full text is slow
Do: Stream text response token by token Don't: Show loading spinner for 10s+
🟢 Feedback Loop (All)¶
AI needs user feedback to improve
Do: Thumps up/down or 'Regenerate' Don't: Static output only
Accessibility¶
🔴 Color Contrast (All)¶
Text must be readable against background
Do: Minimum 4.5:1 ratio for normal text Don't: Low contrast text
🔴 Color Only (All)¶
Don't convey information by color alone
Do: Use icons/text in addition to color Don't: Red/green only for error/success
🔴 Alt Text (All)¶
Images need text alternatives
Do: Descriptive alt text for meaningful images Don't: Empty or missing alt attributes
🟡 Heading Hierarchy (Web)¶
Screen readers use headings for navigation
Do: Use sequential heading levels h1-h6 Don't: Skip heading levels or misuse for styling
🔴 ARIA Labels (All)¶
Interactive elements need accessible names
Do: Add aria-label for icon-only buttons Don't: Icon buttons without labels
🔴 Keyboard Navigation (Web)¶
Web users need complete keyboard navigation with visible focus on every operable control
Do: Keep tab order aligned with visual order and test every action without a pointer Don't: Keyboard traps or illogical tab order
🟡 Screen Reader (All)¶
Content should make sense when read aloud
Do: Use semantic HTML and ARIA properly Don't: Div soup with no semantics
🔴 Form Labels (All)¶
Inputs must have associated labels
Do: Use label with for attribute or wrap input Don't: Placeholder-only inputs
🔴 Error Messages (All)¶
Error messages must be announced
Do: Use aria-live or role=alert for errors Don't: Visual-only error indication
🟡 Skip Links (Web)¶
Allow keyboard users to skip navigation
Do: Provide skip to main content link Don't: No skip link on nav-heavy pages
🔴 Motion Sensitivity (All)¶
Parallax/Scroll-jacking causes nausea
Do: Honor prefers-reduced-motion and present the final readable state without parallax or scroll-jacking Don't: Force scroll effects
🔴 Focus Not Obscured (Minimum) (Web)¶
WCAG 2.2 AA requires keyboard focus to remain at least partially visible
Do: Offset sticky UI with scroll-padding and dismiss or move persistent overlays Don't: Let headers footers banners or chat widgets fully cover focus
🟡 Focus Not Obscured (Enhanced) (Web)¶
WCAG 2.2 AAA requires keyboard focus to remain fully visible
Do: Keep the entire focused component unobscured by author-created content Don't: Present this enhanced AAA criterion as an AA requirement or allow persistent UI to hide any part of focus
// good
close persistent overlay before focus moves behind it
// bad
sticky footer covers half the focused button
🟡 Focus Appearance (Web)¶
WCAG 2.2 AAA defines minimum area and contrast for focus indicators
Do: Use an indicator at least as large as a 2 CSS px perimeter with 3:1 state contrast Don't: Present this enhanced AAA criterion as an AA requirement or use a thin low-contrast outline
// good
outline: 2px solid currentColor; outline-offset: 2px
// bad
box-shadow: 0 0 1px low-contrast
🔴 Dragging Movements (All)¶
WCAG 2.2 AA requires a single-pointer alternative for author-controlled drag operations
Do: Add buttons menus or tap-to-move controls and retain keyboard operation Don't: Make dragging the only way to reorder resize or select
🔴 Target Size (Minimum) (Web)¶
WCAG 2.2 AA requires 24 CSS px pointer targets or an applicable exception
Do: Use at least 24 by 24 CSS px or verify spacing equivalent inline user-agent or essential exceptions Don't: Assume native 44pt or 48dp guidance defines web conformance
🟡 Consistent Help (All)¶
WCAG 2.2 A requires repeated help mechanisms to stay in the same relative order
Do: Keep contact self-help and automated help in consistent locations Don't: Move help controls to different locations on each page
• Text Reflow and Spacing (Web)¶
Text must remain available at narrow widths zoom and user spacing overrides
Do: Use fluid sizes content-driven height and unitless line height Don't: Clip text in fixed-width or fixed-height boxes
// good
.copy { inline-size: min(100%, 65ch); height: auto; line-height: 1.5; }
// bad
.copy { width: 900px; height: 40px; overflow: hidden; }
• Compact Control Semantics (Web)¶
Interactive chips need a native role accessible name state keyboard operation and visible focus
Do: Prefer a button and expose pressed or selected state that matches the visible label Don't: Use a clickable div or reveal the only action on hover
// good
<button aria-pressed='true'>Open now</button>
// bad
<div class='selected' onclick='toggle()'>Open now</div>
🔴 Contextual Live Badge Updates (Web)¶
Async badge and count changes should announce a meaningful contextual status without moving focus
Do: Use one appropriate atomic status message such as 3 items in cart Don't: Announce a bare number or make every badge a competing live region
// good
<span role='status' aria-atomic='true'>3 items in cart</span>
// bad
<span aria-live='polite'>3</span>
Animation¶
🔴 Excessive Motion (All)¶
Too many animations cause distraction and motion sickness
Do: Animate 1-2 key elements per view maximum Don't: Animate everything that moves
🟡 Duration Timing (All)¶
Motion duration depends on distance complexity platform and user context
Do: Use shared motion tokens and test that feedback stays responsive Don't: Present 150-300ms or any cutoff as a universal requirement
🔴 Reduced Motion (All)¶
Respect user's motion preferences
Do: Check prefers-reduced-motion media query Don't: Ignore accessibility motion settings
🔴 Loading States (All)¶
Show feedback during async operations
Do: Use skeleton screens or spinners Don't: Leave UI frozen with no feedback
🔴 Hover vs Tap (All)¶
Hover effects don't work on touch devices
Do: Use click/tap for primary interactions Don't: Rely only on hover for important actions
🟡 Continuous Animation (All)¶
Infinite animations are distracting
Do: Use for loading indicators only Don't: Use for decorative elements
🟡 Transform Performance (Web)¶
Some CSS properties trigger expensive repaints
Do: Use transform and opacity for animations Don't: Animate width/height/top/left properties
🟢 Easing Functions (All)¶
Easing should match how an element changes speed and purpose
Do: Use deceleration when arriving acceleration when leaving and linear for constant-rate progress Don't: Reject linear easing even for steady rotation or progress
🔴 Auto-Rotating Content Controls (All)¶
Auto-rotating content needs user control
Do: Provide previous next and play/pause; stop on focus or hover and when reduced motion is requested Don't: Auto-advance slides without a stop control
🔴 Cancellable State Transitions (Web)¶
Rapid compact-control changes can interrupt an in-flight transition
Do: Cancel or replace prior motion; set the final semantic state directly and handle cancellation cleanup Don't: Depend on animationend or transitionend for required state correctness
Content¶
🟡 Truncation (All)¶
Handle long content gracefully
Do: Truncate with ellipsis and expand option Don't: Overflow or broken layout
🟢 Date Formatting (All)¶
Use locale-appropriate date formats
Do: Use relative or locale-aware dates Don't: Ambiguous date formats
🟢 Number Formatting (All)¶
Format large numbers for readability
Do: Use thousand separators or abbreviations Don't: Long unformatted numbers
🟢 Placeholder Content (All)¶
Show realistic placeholders during dev
Do: Use realistic sample data Don't: Lorem ipsum everywhere
• Essential Text Truncation (All)¶
Headings actions errors safety text and distinguishing names need complete access
Do: Wrap stack resize or provide a visible full-detail path Don't: Clamp essential meaning only to make cards uniform
// good
Action label wraps or opens full details
// bad
Primary action shown only as an unexplained ellipsis
🔴 Compact Label Semantics (All)¶
Badges communicate state while chips or tags represent values or actions
Do: Choose static or interactive markup from the label's meaning and ownership Don't: Make every pill clickable or encode status with color alone
// good
<span class='status'>Pending</span>
// bad
<div class='pill' onclick='toggle()'>Pending</div>
🔴 Compact Label Overflow (All)¶
A badge chip or pill label should stay whole on one line when practical and disclose unavoidable truncation
Do: Bound only unpredictable values; use nowrap with a shrinkable label; expose full text to keyboard pointer and touch users Don't: Let one compact label wrap to a second line or use a hover-only tooltip
// good
Flexible label with min-width 0 and an operable full-value disclosure
// bad
Fixed-width badge wraps to second line or clips with title-only recovery
Data Entry¶
🟢 Bulk Actions (Web)¶
Editing one by one is tedious
Do: Allow multi-select and bulk edit Don't: Single row actions only
Feedback¶
🔴 Loading Indicators (All)¶
Loading feedback should match the expected wait and avoid flashing for near-instant work
Do: Follow platform and component guidance; preserve layout focus and accessible busy status Don't: Apply one timing threshold to every operation or leave long waits unexplained
🟡 Empty States (All)¶
Guide users when no content exists
Do: Show helpful message and action Don't: Blank empty screens
🟡 Error Recovery (All)¶
Help users recover from errors
Do: Provide clear next steps Don't: Error without recovery path
🟡 Progress Indicators (All)¶
Show progress for multi-step processes
Do: Step indicators or progress bar Don't: No indication of progress
🟡 Toast Notifications (All)¶
Transient messages for non-critical info
Do: Auto-dismiss after 3-5 seconds Don't: Toasts that never disappear
🟡 Confirmation Messages (All)¶
Confirm successful actions
Do: Brief success message Don't: Silent success
Forms¶
🔴 Input Labels (All)¶
Every input needs a visible label
Do: Always show label above or beside input Don't: Placeholder as only label
🔴 Error Placement (All)¶
Each invalid field needs an inline error connected to that field
Do: Show a specific error below the input and reference it with aria-describedby Don't: Show only a top-level error without identifying each invalid field
// good
<input aria-describedby="email-error"><p id="email-error">Enter an email address</p>
// bad
Red border or summary only
🟡 Inline Validation (All)¶
Validate as user types or on blur
Do: Validate on blur for most fields Don't: Validate only on submit
🟡 Input Types (All)¶
Use appropriate input types
Do: Use email tel number url etc Don't: Text input for everything
🟡 Autofill Support (Web)¶
Help browsers autofill correctly
Do: Use autocomplete attribute properly Don't: Block or ignore autofill
🟡 Required Indicators (All)¶
Mark required fields clearly
Do: Use asterisk or (required) text Don't: No indication of required fields
🟡 Password Visibility (All)¶
Let users see password while typing
Do: Toggle to show/hide password Don't: No visibility toggle
🔴 Submit Feedback (All)¶
Confirm form submission status
Do: Show loading then success/error state Don't: No feedback after submit
🟡 Input Affordance (All)¶
Inputs should look interactive
Do: Use distinct input styling Don't: Inputs that look like plain text
🟡 Mobile Keyboards (Mobile)¶
Show appropriate keyboard for input type
Do: Use inputmode attribute Don't: Default keyboard for all inputs
🟡 Redundant Entry (All)¶
WCAG 2.2 A avoids requiring the same information twice in one process
Do: Auto-populate prior values or let users select previously entered information Don't: Ask users to retype the same address or account data without necessity
Forms / Accessibility¶
🔴 Focusable Error Summary (Web)¶
An error summary for failed validation complements inline field errors and must be easy to find by keyboard and screen reader users
Do: Place it at the top of the form; move focus to its heading or container after failed submit; link each item to its invalid field; retain inline errors Don't: Replace inline errors with a visual-only summary or move focus on every blur
// good
<div role="alert" tabindex="-1" aria-labelledby="error-title"><h2 id="error-title">There is a problem</h2><a href="#email">Enter an email address</a></div>
// bad
Toast only with no field links or focus target
Interaction¶
🔴 Focus States (All)¶
Keyboard focus, including controls inside a modal, needs a visible indicator
Do: Use a visible focus ring on every interactive control, including modal controls Don't: Remove focus outline without replacement
🟡 Hover States (Web)¶
Visual feedback on interactive elements
Do: Change cursor and add subtle visual change Don't: No hover feedback on clickable elements
🟡 Active States (All)¶
Show immediate feedback on press/click
Do: Add pressed/active state visual change Don't: No feedback during interaction
🟡 Disabled States (All)¶
Clearly indicate non-interactive elements
Do: Reduce opacity and change cursor Don't: Confuse disabled with normal state
🔴 Loading Buttons (All)¶
Prevent double submission during async actions
Do: Disable button and show loading state Don't: Allow multiple clicks during processing
🔴 Error Feedback (All)¶
Users need to know when something fails
Do: Show clear error messages near problem Don't: Silent failures with no feedback
🟡 Success Feedback (All)¶
Confirm successful actions to users
Do: Show success message or visual change Don't: No confirmation of completed action
🔴 Confirmation Dialogs (All)¶
Prevent accidental destructive actions
Do: Confirm before delete/irreversible actions Don't: Delete without confirmation
Layout¶
🔴 Z-Index Management (Web)¶
Stacking context conflicts cause hidden elements
Do: Define z-index scale system (10 20 30 50) Don't: Use arbitrary large z-index values
🟡 Overflow Hidden (Web)¶
Hidden overflow can clip important content
Do: Test all content fits within containers Don't: Blindly apply overflow-hidden
🟡 Fixed Positioning (Web)¶
Fixed elements can overlap or be inaccessible
Do: Account for safe areas and other fixed elements Don't: Stack multiple fixed elements carelessly
🟡 Stacking Context (Web)¶
New stacking contexts reset z-index
Do: Understand what creates new stacking context Don't: Expect z-index to work across contexts
🔴 Content Jumping (Web)¶
Images badges validation text and skeleton replacements can shift nearby content when they update
Do: Reserve appropriate space or keep async states in a stable content-driven container Don't: Insert compact text or media without a layout strategy
// good
aspect-ratio for media; stable count slot for badges
// bad
Badge insertion pushes toolbar actions
🟡 Viewport Units (Web)¶
100vh can be problematic on mobile browsers
Do: Use dvh or account for mobile browser chrome Don't: Use 100vh for full-screen mobile layouts
🟡 Container Width (Web)¶
Content too wide is hard to read
Do: Limit max-width for text content (65-75ch) Don't: Let text span full viewport width
🔴 Long Token Wrapping (Web)¶
URLs identifiers and user content must not force horizontal overflow
Do: Use overflow-wrap anywhere and let flex or grid text children shrink Don't: Apply word-break break-all to all prose
// good
.token { min-inline-size: 0; overflow-wrap: anywhere; }
// bad
.token { white-space: nowrap; }
🔴 Chip Collection Reflow (All)¶
Filter chips and editable value collections must preserve labels when space or text size changes
Do: Wrap the collection or use an operable +n disclosure for hidden overflow values Don't: Force all chips into one clipped row or hide overflow values
// good
<div class='chip-list'>{chips}</div> with flex-wrap
// bad
<div class='chip-list' style='height:32px;overflow:hidden'>
Navigation¶
🔴 Smooth Scroll (Web)¶
Anchor links should scroll smoothly to target section
Do: Use scroll-behavior: smooth on html element Don't: Jump directly without transition
🟡 Sticky Navigation (Web)¶
Fixed nav should not obscure content
Do: Add padding-top to body equal to nav height Don't: Let nav overlap first section content
🟡 Active State (All)¶
Current page/section should be visually indicated
Do: Highlight active nav item with color/underline Don't: No visual feedback on current location
🔴 Back Button (Mobile)¶
Users expect back to work predictably
Do: Preserve navigation history properly Don't: Break browser/app back button behavior
🟡 Deep Linking (All)¶
URLs should reflect current state for sharing
Do: Update URL on state/view changes Don't: Static URLs for dynamic content
🟢 Breadcrumbs (Web)¶
Show user location in site hierarchy
Do: Use for sites with 3+ levels of depth Don't: Use for flat single-level sites
Onboarding¶
🟡 User Freedom (All)¶
Users should be able to skip tutorials
Do: Provide Skip and Back buttons Don't: Force linear unskippable tour
Performance¶
🔴 Image Optimization (All)¶
Large images slow page load
Do: Use appropriate size and format (WebP) Don't: Unoptimized full-size images
🟡 Lazy Loading (All)¶
Load content as needed
Do: Lazy load below-fold images and content Don't: Load everything upfront
🟡 Code Splitting (Web)¶
Large bundles slow initial load
Do: Split code by route/feature Don't: Single large bundle
🟡 Caching (Web)¶
Repeat visits should be fast
Do: Set appropriate cache headers Don't: No caching strategy
🟡 Font Loading (Web)¶
Web fonts can block rendering
Do: Use font-display swap or optional Don't: Invisible text during font load
🟡 Third Party Scripts (Web)¶
External scripts can block rendering
Do: Load non-critical scripts async/defer Don't: Synchronous third-party scripts
🟡 Bundle Size (Web)¶
Large JavaScript slows interaction
Do: Monitor and minimize bundle size Don't: Ignore bundle size growth
🟡 Render Blocking (Web)¶
CSS/JS can block first paint
Do: Inline critical CSS defer non-critical Don't: Large blocking CSS files
Responsive¶
🟡 Mobile First (Web)¶
Design for mobile then enhance for larger
Do: Start with mobile styles then add breakpoints Don't: Desktop-first causing mobile issues
🟡 Breakpoint Testing (Web)¶
Test at all common screen sizes
Do: Test at 320 375 414 768 1024 1440 Don't: Only test on your device
🔴 Touch Friendly (Web)¶
Mobile layouts need touch-sized targets
Do: Increase touch targets on mobile Don't: Same tiny buttons on mobile
🔴 Readable Font Size (All)¶
Text must be readable on all devices
Do: Minimum 16px body text on mobile Don't: Tiny text on mobile
🔴 Viewport Meta (Web)¶
Set viewport for mobile devices
Do: Use width=device-width initial-scale=1 Don't: Missing or incorrect viewport
🔴 Horizontal Scroll (Web)¶
Avoid horizontal scrolling
Do: Ensure content fits viewport width Don't: Content wider than viewport
🟡 Image Scaling (Web)¶
Images should scale with container
Do: Use max-width: 100% on images Don't: Fixed width images overflow
🟡 Table Handling (Web)¶
Tables can overflow on mobile
Do: Use horizontal scroll or card layout Don't: Wide tables breaking layout
Search¶
🟡 Autocomplete (Web)¶
Help users find results faster
Do: Show predictions as user types Don't: Require full type and enter
🟡 No Results (Web)¶
Dead ends frustrate users
Do: Show 'No results' with suggestions Don't: Blank screen or '0 results'
Security / Accessibility¶
• Accessible Authentication (Minimum) (All)¶
WCAG 2.2 AA says authentication must not depend only on a cognitive function test unless an exception applies
Do: Allow password managers and paste; offer passkeys OAuth or another non-cognitive method Don't: Block paste or require manual OTP transcription with no alternative
Spatial UI¶
🔴 Gaze Hover (VisionOS)¶
Elements should respond to eye tracking before pinch
Do: Scale/highlight element on look Don't: Static element until pinch
🟡 Depth Layering (VisionOS)¶
UI needs Z-depth to separate content from environment
Do: Use glass material and z-offset Don't: Flat opaque panels blocking view
Sustainability¶
🟡 Auto-Play Video (Web)¶
Autoplaying media consumes data and creates motion barriers
Do: Prefer click-to-play; provide pause and captions; stop off-screen and honor reduced motion Don't: Auto-play high-resolution loops without pause or captions
🟡 Asset Weight (Web)¶
Heavy 3D/Image assets increase carbon footprint
Do: Compress and lazy load 3D models Don't: Load 50MB textures
Touch¶
🔴 Touch Target Size (Mobile)¶
Touch target guidance depends on platform and web context
Do: Use 44pt on iOS and 48dp on Android; for web use the separate WCAG Target Size rule Don't: Treat one unit or minimum as universal across platforms
🟡 Touch Spacing (Mobile)¶
Adjacent touch targets need adequate spacing
Do: Minimum 8px gap between touch targets Don't: Tightly packed clickable elements
🟡 Gesture Conflicts (Mobile)¶
Custom gestures can conflict with system
Do: Avoid horizontal swipe on main content Don't: Override system gestures
🟡 Tap Delay (Mobile)¶
300ms tap delay feels laggy
Do: Use touch-action CSS or fastclick Don't: Default mobile tap handling
🟢 Pull to Refresh (Mobile)¶
Accidental refresh is frustrating
Do: Disable where not needed Don't: Enable by default everywhere
🟢 Haptic Feedback (Mobile)¶
Tactile feedback improves interaction feel
Do: Use for confirmations and important actions Don't: Overuse vibration feedback
Typography¶
🟡 Line Height (All)¶
Adequate line height improves readability
Do: Use 1.5-1.75 for body text Don't: Cramped or excessive line height
🟡 Line Length (Web)¶
Long lines are hard to read
Do: Limit to 65-75 characters per line Don't: Full-width text on large screens
🟡 Font Size Scale (All)¶
Consistent type hierarchy aids scanning
Do: Use consistent modular scale Don't: Random font sizes
🟡 Font Loading (Web)¶
Fonts should load without layout shift
Do: Reserve space with fallback font Don't: Layout shift when fonts load
🔴 Contrast Readability (All)¶
Body text needs good contrast
Do: Use darker text on light backgrounds Don't: Gray text on gray background
🟡 Heading Clarity (All)¶
Headings should stand out from body
Do: Clear size/weight difference Don't: Headings similar to body text
🟡 Heading Line Balance (Web)¶
Short multi-line headings may use balanced wrapping as a progressive visual heuristic
Do: Bound the measure and test natural-wrap fallback across widths fonts and locales Don't: Promise an exact final line or insert blanket nonbreaking spaces or hardcoded br tags