--- name: web-ui-best-practices description: Opinionated constraints for building better user interfaces. Triggers on building or reviewing web components, pages, forms, modals, animations, or any frontend UI work. Covers accessibility, focus states, touch interactions, and performance. --- # Web UI Best Practices When invoked generally, apply these opinionated constraints for building better interfaces and for any UI work in this conversation. When invoked with a file specified (i.e. `web-ui-best-practices `), review the file against all constraints below and output: 1. violations (quote the exact line/snippet) 2. why it matters (1 short sentence) 3. a concrete fix (code-level suggestion) ## Stack - MUST use Tailwind CSS defaults unless custom values already exist or are explicitly requested - MUST use `motion/react` (formerly `framer-motion`) when JavaScript animation is required - SHOULD use `tw-animate-css` for entrance and micro-animations in Tailwind CSS - MUST use `cn` utility (`clsx` + `tailwind-merge`) for class logic ## Components - MUST use accessible component primitives for anything with keyboard or focus behavior (`Base UI`, `Radix`, `React-Aria`) - MUST use the project’s existing component primitives first - NEVER mix primitive systems within the same interaction surface - SHOULD prefer [`Base UI`](https://base-ui.com/react/components) for new primitives if compatible with the stack - MUST add an `aria-label` to icon-only buttons - NEVER rebuild keyboard or focus behavior by hand unless explicitly requested ## Interaction - MUST use an `AlertDialog` for destructive or irreversible actions - SHOULD use structural skeletons for loading states - NEVER use `h-screen`, use `h-dvh` - MUST show errors next to where the action happens - NEVER block paste in `input` or `textarea` elements ## Navigation & State - SHOULD reflect UI state in the URL (filters, tabs, pagination, expanded panels via query params) - MUST use `` / `` for navigation (Cmd/Ctrl+click and middle-click should work) - SHOULD deep-link stateful UI (if it uses `useState`, consider URL sync via `nuqs` or similar) - MUST require confirmation or undo window for destructive actions (never immediate) ## Touch & Interaction - SHOULD set `touch-action: manipulation` on tappable controls (prevents double-tap zoom delay) - SHOULD set `-webkit-tap-highlight-color` intentionally - MUST use `overscroll-behavior: contain` in modals/drawers/sheets - SHOULD during drag: disable text selection, `inert` on dragged elements - SHOULD use `autoFocus` sparingly (desktop only, single primary input; avoid on mobile) ## Animation - NEVER add animation unless it is explicitly requested - MUST animate only compositor props (`transform`, `opacity`) - NEVER animate layout properties (`width`, `height`, `top`, `left`, `margin`, `padding`) - SHOULD avoid animating paint properties (`background`, `color`) except for small, local UI (text, icons) - SHOULD use `ease-out` on entrance - NEVER exceed `200ms` for interaction feedback - MUST pause looping animations when off-screen - SHOULD respect `prefers-reduced-motion` - NEVER introduce custom easing curves unless explicitly requested - SHOULD avoid animating large images or full-screen surfaces - SHOULD never `transition: all`—list properties explicitly - SHOULD set correct `transform-origin` - SHOULD have animations be interruptible—respond to user input mid-animation ## Typography - MUST use `text-balance` for headings and `text-pretty` for body/paragraphs - MUST use `tabular-nums` for data - SHOULD use `truncate` or `line-clamp` for dense UI - NEVER modify `letter-spacing` (`tracking-*`) unless explicitly requested - SHOULD use `…` not `...` - SHOULD use curly quotes `"` `"` not straight `"` - SHOULD have non-breaking spaces: `10 MB`, `⌘ K`, brand names - SHOULD have loading states end with `…`: `"Loading…"`, `"Saving…"` - SHOULD use `font-variant-numeric: tabular-nums` for number columns/comparisons - SHOULD have flex children need `min-w-0` to allow text truncation - SHOULD handle empty states—don't render broken UI for empty strings/arrays - SHOULD consider that user-generated input fields may have short, average, and very long inputs ## Layout - MUST use a fixed `z-index` scale (no arbitrary `z-*`) - SHOULD use `size-*` for square elements instead of `w-*` + `h-*` ## Safe Areas & Layout - MUST respect `env(safe-area-inset-*)` for full-bleed layouts and fixed elements on notched devices - SHOULD avoid unwanted scrollbars (use `overflow-x-hidden` on containers and fix overflow at the source) - SHOULD prefer flex/grid over JS measurement for layout ## Dark Mode & Theming - MUST set `color-scheme: dark` on `` for dark themes (fixes scrollbars and native inputs) - SHOULD set `` to match the page background - SHOULD set explicit `background-color` and `color` on native `