Web Interface Guidelines
Review UI code for compliance with Vercel's web interface standards.
Quick Reference - Visual Stability
| Issue | Rule |
|-------|------|
| Images without dimensions | <img> needs explicit width and height (prevents CLS) |
| Font loading flash | Critical fonts: <link rel="preload" as="font"> with font-display: swap |
| Large lists | Virtualize lists >50 items (content-visibility: auto) |
| Layout reads in render | No getBoundingClientRect, offsetHeight in render path |
Full Rules
Images
<img>needs explicitwidthandheight(prevents CLS)- Below-fold images:
loading="lazy" - Above-fold critical images:
priorityorfetchpriority="high"
Performance
- Large lists (>50 items): virtualize (
virtua,content-visibility: auto) - No layout reads in render (
getBoundingClientRect,offsetHeight,offsetWidth,scrollTop) - Batch DOM reads/writes; avoid interleaving
- Add
<link rel="preconnect">for CDN/asset domains - Critical fonts:
<link rel="preload" as="font">withfont-display: swap
Accessibility
- Icon-only buttons need
aria-label - Form controls need
<label>oraria-label - Interactive elements need keyboard handlers (
onKeyDown/onKeyUp) <button>for actions,<a>/<Link>for navigation (not<div onClick>)- Images need
alt(oralt=""if decorative)
Focus States
- Interactive elements need visible focus:
focus-visible:ring-*or equivalent - Never
outline-none/outline: nonewithout focus replacement - Use
:focus-visibleover:focus(avoid focus ring on click)
Animation
- Honor
prefers-reduced-motion(provide reduced variant or disable) - Animate
transform/opacityonly (compositor-friendly) - Never
transition: all—list properties explicitly
Forms
- Inputs need
autocompleteand meaningfulname - Use correct
type(email,tel,url,number) andinputmode - Never block paste (
onPaste+preventDefault) - Labels clickable (
htmlForor wrapping control)
Content Handling
- Text containers handle long content:
truncate,line-clamp-*, orbreak-words - Flex children need
min-w-0to allow text truncation - Handle empty states—don't render broken UI for empty strings/arrays
Anti-patterns (flag these)
user-scalable=noormaximum-scale=1disabling zoomtransition: alloutline-nonewithout focus-visible replacement- Images without dimensions
- Large arrays
.map()without virtualization - Form inputs without labels
- Icon buttons without
aria-label