Applies Vercel web interface guidelines: accessibility, CLS/visual stability, performance, forms, and reduced-motion. Use when reviewing or building UI markup, styles, or animation for a11y/performance/visual-stability compliance. Not for React/Next scaffolding or bundle scripts (senior-frontend). Not a motion-taste chair (emil-design-eng).
Applies Vercel web interface guidelines: accessibility, CLS/visual stability, performance, forms, and reduced-motion. Use when reviewing or building UI markup, styles, or animation for a11y/performance/visual-stability compliance. Not for React/Next scaffolding or bundle scripts (senior-frontend). Not a motion-taste chair (emil-design-eng).
risk
safe
source
openrouter-deepsearch
date_added
2026-06-14T00:00:00.000Z
Web Interface Guidelines
Review and enforce Vercel's web interface standards across UI code—accessibility, performance, visual stability, animation, forms, and content handling.
When to Use
Building or reviewing any web UI component (React, Vue, plain HTML/CSS).
Auditing markup, styles, or JavaScript logic for accessibility or performance regressions.
Adding images, fonts, lists, forms, or animations to a web interface.
Triggered by keywords: UI review, accessibility audit, CLS, focus state, reduced motion, form input, virtualization, image dimensions, font preload.
Do Not Use
Non-web platforms (native mobile, desktop apps).
Legacy codebases where these guidelines require a full migration plan—prioritize critical security and accessibility fixes first, then adopt incrementally.
Enforcing arbitrary stylistic preferences that do not impact performance, accessibility, or visual stability.
Prerequisites
Familiarity with the target framework (React, Vue, Next.js, etc.).
Access to browser DevTools (Lighthouse, Network, Performance tabs).
No getBoundingClientRect, offsetHeight in render path; use requestAnimationFrame for DOM reads/writes
Full Rules
Images
<img> needs explicit width and height attributes or CSS aspect-ratio (prevents CLS). Use aspect-ratio for responsive images.
Below-fold images: loading="lazy".
Above-fold critical images: fetchpriority="high" or priority attribute (Next.js Image component).
Use modern formats (WebP, AVIF) with <picture> and <source>.
Ensure srcset and sizes are correctly used for responsive delivery.
Performance
Large lists (>50 items): virtualize with @tanstack/react-virtual, vue-virtual-scroller, or content-visibility: auto for non-interactive sections.
No layout reads in render (getBoundingClientRect, offsetHeight, offsetWidth, scrollTop, scrollWidth, scrollHeight). Batch DOM reads/writes via requestAnimationFrame or IntersectionObserver.
Add <link rel="preconnect"> for CDN/asset domains; <link rel="dns-prefetch"> for older browsers.
Critical fonts: <link rel="preload" as="font" type="font/woff2" crossorigin> with font-display: swap or optional. Use WOFF2.
Optimize CSS: inline critical CSS, lazy-load non-critical. Prefer CSS-in-JS with atomic CSS or static extraction.
Avoid excessive re-renders: React.memo, useMemo, useCallback, or Vue reactivity transforms.
Accessibility
Icon-only buttons need aria-label or visually hidden text.
Form controls need <label> via htmlFor or aria-labelledby, or aria-label for standalone controls.
Interactive elements need keyboard handlers (onKeyDown/onKeyUp); ensure Tab, Enter, Space work.
Use native elements: <button> for actions, <a>/<Link> for navigation. Avoid <div>/<span> with onClick; if unavoidable, add role="button" and keyboard handlers.
Images need meaningful alt (or alt="" if decorative). Complex images: aria-describedby pointing to longer description.
Ensure color contrast (WCAG 2.1 AA or AAA).
Provide clear focus indicators for all interactive elements.
Use semantic HTML5 (<nav>, <main>, <aside>, <article>, <section>, <footer>, <header>).
Implement ARIA live regions (aria-live="polite") for dynamic content updates.
Focus States
Interactive elements need visible focus: focus-visible:ring-*, focus-visible:outline-*, or equivalent.
Never use outline-none / outline: none without a clear, accessible focus indicator replacement.
Use :focus-visible over :focus to prevent focus rings on click interactions.
Ensure focus order follows visual order.
Animation
Honor prefers-reduced-motion (e.g., useReducedMotion from framer-motion). Provide reduced motion variant or disable animations.
Animate only transform (translate, scale, rotate) and opacity—compositor-friendly. Avoid animating width, height, margin, padding, top, left.
Never use transition: all—list properties explicitly.
Use will-change judiciously; remove when animation completes to avoid memory overhead.
For complex animations: Framer Motion, React Spring, or GSAP.
Forms
Inputs need autocomplete attributes (e.g., autocomplete="email", autocomplete="current-password").
Use meaningful name attributes.
Use correct type (email, tel, url, number, date, time, search) and inputmode (e.g., inputmode="numeric") for mobile keyboards.
Never block paste (onPaste + preventDefault) unless critical security reason; provide clear feedback if blocked.
Labels must be clickable and associated via htmlFor or by wrapping the control.
Implement client-side and server-side validation with clear error messages. Use aria-invalid and aria-describedby.
Content Handling
Text containers handle long content: text-overflow: ellipsis + overflow: hidden + white-space: nowrap for single lines; line-clamp-* for multi-line; word-break: break-word / overflow-wrap: break-word for wrapping.
Flex children need min-w-0 (or min-width: 0) to allow truncation within flex containers.
Handle empty states gracefully—no broken UI for empty strings/arrays. Provide "no data" messages or placeholders.
Use responsive typography: clamp(), rem units, media queries.
Pitfalls
user-scalable=no or maximum-scale=1 in viewport meta—critical accessibility violation. Always flag.
transition: all without explicit property listing—causes unintended performance issues.
outline-none / outline: none without :focus-visible replacement—removes keyboard accessibility.
Images without width/height or aspect-ratio—causes CLS.
Large arrays .map() without virtualization for lists >~50 items—performance degradation.
Form inputs without <label> or aria-label—accessibility failure.
Icon buttons without aria-label—unusable by screen readers.
<div>/<span> with onClick instead of <button>/<a>—missing keyboard support and semantics.
Inline styles for critical layout that should be CSS classes—maintainability and performance issues.
Excessive !important in CSS—specificity wars and maintainability issues.
Blocking main thread with long-running JS—use requestIdleCallback or Web Workers.