UI/UX best practices for web interfaces. Use when reviewing animations, CSS, audio, typography, UX patterns, prefetching, or icon implementations. Covers 11 categories from animation principles to typography. Outputs file:line findings.
Comprehensive UI/UX best practices guide for web interfaces. Contains 152 rules across 12 categories, prioritized by impact to guide automated code review and generation.
Reference these guidelines when:
| Priority | Category | Impact | Prefixes |
|---|
| 1 | Animation Principles | CRITICAL | timing-, physics-, staging- |
| 2 | Timing Functions | HIGH | spring-, easing-, duration-, none- |
| 3 | Exit Animations | HIGH | exit-, presence-, mode-, nested- |
| 4 | CSS Pseudo Elements | MEDIUM | pseudo-, transition-, native- |
| 5 | Audio Feedback | MEDIUM | a11y-, appropriate-, impl-, weight- |
| 6 | Sound Synthesis | MEDIUM | context-, envelope-, design-, param- |
| 7 | Morphing Icons | LOW | morphing- |
| 8 | Container Animation | MEDIUM | container- |
| 9 | Laws of UX | HIGH | ux- |
| 10 | Predictive Prefetching | MEDIUM | prefetch- |
| 11 | Typography | MEDIUM | type- |
| 12 | Visual Design | HIGH | visual- |
timing-under-300ms - User animations must complete within 300mstiming-consistent - Similar elements use identical timing valuestiming-no-entrance-context-menu - Context menus: no entrance animation, exit onlyeasing-natural-decay - Use exponential ramps for natural decay, not lineareasing-no-linear-motion - Linear easing only for progress indicatorsphysics-active-state - Interactive elements need :active scale transformphysics-subtle-deformation - Squash/stretch in 0.95-1.05 rangephysics-spring-for-overshoot - Springs for overshoot-and-settle, not easingphysics-no-excessive-stagger - Stagger delays under 50ms per itemstaging-one-focal-point - One prominent animation at a timestaging-dim-background - Dim modal/dialog backgroundsstaging-z-index-hierarchy - Animated elements respect z-index layersspring-for-gestures - Gesture-driven motion (drag, flick) must use springsspring-for-interruptible - Interruptible motion must use springsspring-preserves-velocity - Springs preserve input energy on releasespring-params-balanced - Avoid excessive oscillation in spring paramseasing-for-state-change - System state changes use easing curveseasing-entrance-ease-out - Entrances use ease-outeasing-exit-ease-in - Exits use ease-ineasing-transition-ease-in-out - View transitions use ease-in-outeasing-linear-only-progress - Linear only for progress/time representationduration-press-hover - Press/hover: 120-180msduration-small-state - Small state changes: 180-260msduration-max-300ms - User-initiated max 300msduration-shorten-before-curve - Fix slow feel with shorter duration, not curvenone-high-frequency - No animation for high-frequency interactionsnone-keyboard-navigation - Keyboard navigation instant, no animationnone-context-menu-entrance - Context menus: no entrance, exit onlyexit-requires-wrapper - Conditional motion elements need AnimatePresence wrapperexit-prop-required - Elements in AnimatePresence need exit propexit-key-required - Dynamic lists need unique keys, not indexexit-matches-initial - Exit mirrors initial for symmetrypresence-hook-in-child - useIsPresent in child, not parentpresence-safe-to-remove - Call safeToRemove after async cleanuppresence-disable-interactions - Disable interactions on exiting elementsmode-wait-doubles-duration - Mode "wait" doubles duration; halve timingmode-sync-layout-conflict - Mode "sync" causes layout conflictsmode-pop-layout-for-lists - Use popLayout for list reorderingnested-propagate-required - Nested AnimatePresence needs propagate propnested-consistent-timing - Coordinate parent-child exit durationspseudo-content-required - ::before/::after need content propertypseudo-over-dom-node - Pseudo-elements over extra DOM nodes for decorationpseudo-position-relative-parent - Parent needs position: relativepseudo-z-index-layering - Z-index for correct pseudo-element layeringpseudo-hit-target-expansion - Negative inset for larger hit targetspseudo-marker-styling - Use ::marker for custom list bullet stylespseudo-first-line-styling - Use ::first-line for typographic treatmentstransition-name-required - View transitions need view-transition-nametransition-name-unique - Each transition name unique during transitiontransition-name-cleanup - Remove transition name after completiontransition-over-js-library - Prefer View Transitions API over JS librariestransition-style-pseudo-elements - Style ::view-transition-group for custom animationsnative-backdrop-styling - Use ::backdrop for dialog backgroundsnative-placeholder-styling - Use ::placeholder for input stylingnative-selection-styling - Use ::selection for text selection stylinga11y-visual-equivalent - Every sound must have a visual equivalenta11y-toggle-setting - Provide toggle to disable soundsa11y-reduced-motion-check - Respect prefers-reduced-motion for sounda11y-volume-control - Allow independent volume adjustmentappropriate-no-high-frequency - No sound on typing or keyboard navappropriate-confirmations-only - Sound for payments, uploads, submissionsappropriate-errors-warnings - Sound for errors that can't be overlookedappropriate-no-decorative - No sound on hover or decorative momentsappropriate-no-punishing - Inform, don't punish with harsh soundsimpl-preload-audio - Preload audio files to avoid delayimpl-default-subtle - Default volume subtle (0.3), not loudimpl-reset-current-time - Reset currentTime before replayweight-match-action - Sound weight matches action importanceweight-duration-matches-action - Sound duration matches action durationcontext-reuse-single - Reuse single AudioContext, don't create per soundcontext-resume-suspended - Resume suspended AudioContext before playingcontext-cleanup-nodes - Disconnect audio nodes after playbackenvelope-exponential-decay - Exponential ramps for natural decayenvelope-no-zero-target - Exponential ramps target 0.001, not 0envelope-set-initial-value - Set initial value before rampingdesign-noise-for-percussion - Filtered noise for clicks/tapsdesign-oscillator-for-tonal - Oscillators with pitch sweep for tonal soundsdesign-filter-for-character - Bandpass filter to shape percussive soundsparam-click-duration - Click sounds: 5-15ms durationparam-filter-frequency-range - Click filter: 3000-6000Hzparam-reasonable-gain - Gain under 1.0 to prevent clippingparam-q-value-range - Filter Q: 2-5 for focused but naturalmorphing-three-lines - Every icon uses exactly 3 SVG linesmorphing-use-collapsed - Unused lines use collapsed constantmorphing-consistent-viewbox - All icons share same viewBox (14x14)morphing-group-variants - Rotational variants share group and base linesmorphing-spring-rotation - Spring physics for grouped icon rotationmorphing-reduced-motion - Respect prefers-reduced-motionmorphing-jump-non-grouped - Instant rotation jump between non-grouped iconsmorphing-strokelinecap-round - Round stroke line capsmorphing-aria-hidden - Icon SVGs are aria-hiddencontainer-two-div-pattern - Outer animated div, inner measured div; never same elementcontainer-guard-initial-zero - Guard bounds === 0 on initial render, fall back to "auto"container-use-resize-observer - Use ResizeObserver for measurement, not getBoundingClientRectcontainer-overflow-hidden - Set overflow: hidden on animated container during transitionscontainer-no-excessive-use - Use sparingly: buttons, accordions, interactive elementscontainer-callback-ref - Use callback ref (not useRef) for measurement hookscontainer-transition-delay - Add small delay for natural catching-up feelux-fitts-target-size - Size interactive targets for easy clicking (min 32px)ux-fitts-hit-area - Expand hit areas with invisible padding or pseudo-elementsux-hicks-minimize-choices - Minimize choices to reduce decision timeux-millers-chunking - Chunk data into groups of 5-9 for scannabilityux-doherty-under-400ms - Respond within 400ms to feel instantux-doherty-perceived-speed - Fake speed with skeletons, optimistic UI, progress indicatorsux-postels-accept-messy-input - Accept messy input, output clean dataux-progressive-disclosure - Show what matters now, reveal complexity laterux-jakobs-familiar-patterns - Use familiar UI patterns users know from other sitesux-aesthetic-usability - Visual polish increases perceived usabilityux-proximity-grouping - Group related elements spatially with tighter spacingux-similarity-consistency - Similar elements should look alikeux-common-region-boundaries - Use boundaries to group related contentux-von-restorff-emphasis - Make important elements visually distinctux-serial-position - Place key items first or last in sequencesux-peak-end-finish-strong - End experiences with clear success statesux-teslers-complexity - Move complexity to the system, not the userux-goal-gradient-progress - Show progress toward completionux-zeigarnik-show-incomplete - Show incomplete state to drive completionux-pragnanz-simplify - Simplify complex visuals into clear formsux-pareto-prioritize-features - Prioritize the critical 20% of featuresux-cognitive-load-reduce - Minimize extraneous cognitive loadux-uniform-connectedness - Visually connect related elements with lines or framesprefetch-trajectory-over-hover - Trajectory prediction over hover; reclaims 100-200msprefetch-not-everything - Prefetch by intent, not viewport; avoid wasted bandwidthprefetch-hit-slop - Use hitSlop to trigger predictions earlierprefetch-touch-fallback - Fall back gracefully on touch devices (no cursor)prefetch-keyboard-tab - Prefetch on keyboard navigation when focus approachesprefetch-use-selectively - Use predictive prefetching where latency is noticeabletype-tabular-nums-for-data - Tabular numbers for columns, dashboards, pricingtype-oldstyle-nums-for-prose - Oldstyle numbers blend into body texttype-slashed-zero - Slashed zero in code-adjacent UIstype-opentype-contextual-alternates - Keep calt enabled for contextual glyph adjustmenttype-disambiguation-stylistic-set - Enable ss02 to distinguish I/l/1 and 0/Otype-optical-sizing-auto - Leave font-optical-sizing auto for size-adaptive glyphstype-antialiased-on-retina - Antialiased font smoothing on retina displaystype-text-wrap-balance-headings - text-wrap: balance on headings for even linestype-underline-offset - Offset underlines below descenderstype-no-font-synthesis - Disable font-synthesis to prevent faux bold/italictype-font-display-swap - Use font-display: swap to avoid invisible text during loadtype-variable-weight-continuous - Use continuous weight values (100-900) with variable fontstype-text-wrap-pretty - text-wrap: pretty for body text to reduce orphanstype-justify-with-hyphens - Pair text-align: justify with hyphens: autotype-letter-spacing-uppercase - Add letter-spacing to uppercase and small-caps texttype-proper-fractions - Use diagonal-fractions for proper typographic fractionsvisual-concentric-radius - Inner radius = outer radius minus padding for nested elementsvisual-layered-shadows - Layer multiple shadows for realistic depthvisual-shadow-direction - All shadows share same offset direction (single light source)visual-no-pure-black-shadow - Use neutral colors, not pure black, for shadowsvisual-shadow-matches-elevation - Shadow size indicates elevation in consistent scalevisual-animate-shadow-pseudo - Animate shadow via pseudo-element opacity for performancevisual-consistent-spacing-scale - Use a consistent spacing scale, not arbitrary valuesvisual-border-alpha-colors - Semi-transparent borders adapt to any backgroundvisual-button-shadow-anatomy - Six-layer shadow anatomy for polished buttonsRead individual rule files for detailed explanations and code examples:
rules/timing-under-300ms.md
rules/spring-for-gestures.md
rules/ux-doherty-under-400ms.md
rules/type-tabular-nums-for-data.md
Each rule file contains:
For the complete guide with all rules expanded: AGENTS.md