Web Interface Guidelines Reviewer
A comprehensive UI code review skill that audits frontend files against
established Web Interface Guidelines. Covers accessibility, performance,
typography, animation, forms, theming, and interaction patterns.
Compatible with: Claude, Claude Code, VS Code agent extensions, Cursor,
Windsurf, and any agent that supports the Agent Skills standard.
Behaviour
- If the user provides a file path or glob pattern, begin the review immediately.
- If no files are specified, ask: "Which files or patterns would you like me to review?"
- Fetch the latest guidelines from the source URL before every review — never use a cached version.
- Read and parse all matched files.
- Check every file against all rule categories below.
- Output findings in the
file:line format defined in the Output Format section.
- If a file passes all checks, output
✓ pass — never skip it silently.
Guidelines Source
Always fetch the authoritative, up-to-date rules before reviewing:
https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md
Use a WebFetch or equivalent tool to retrieve this file fresh on every invocation.
The fetched content is the source of truth. Rules below are a local reference
and may lag behind the canonical source.
Rule Categories (Local Reference)
Accessibility
- Icon-only buttons require
aria-label
- Form controls require
<label> or aria-label
- Interactive elements require keyboard handlers (
onKeyDown / onKeyUp)
- Use
<button> for actions, <a> / <Link> for navigation — not <div onClick>
- Images require
alt; decorative images use alt=""
- Decorative icons require
aria-hidden="true"
- Async updates (toasts, validation messages) require
aria-live="polite"
- Prefer semantic HTML over ARIA where a native element exists
- Headings must be hierarchical
<h1>–<h6>; include a skip link for main content
- Heading anchors need
scroll-margin-top
Focus States
- All interactive elements need a visible focus indicator (
focus-visible:ring-* or equivalent)
- Never use
outline-none / outline: none without a replacement focus style
- Use
:focus-visible over :focus to avoid showing ring on mouse click
- Use
:focus-within for compound controls
Forms
- Inputs need
autocomplete and a meaningful name attribute
- Use correct
type (email, tel, url, number) and inputmode
- Never block paste (
onPaste + preventDefault)
- Labels must be clickable via
htmlFor or by wrapping the control
- Disable spellcheck on emails, codes, and usernames (
spellCheck={false})
- Checkbox and radio label + control share a single hit target — no dead zones
- Submit button stays enabled until the request starts; show spinner during request
- Inline errors displayed next to the relevant field; focus first error on submit
- Placeholders end with
… and show an example pattern
- Use
autocomplete="off" on non-auth fields to avoid password manager conflicts
- Warn before navigation when unsaved changes exist (
beforeunload or router guard)
Animation
- Respect
prefers-reduced-motion — provide a reduced variant or disable animation entirely
- Only animate
transform and opacity (compositor-friendly properties)
- Never use
transition: all — list properties explicitly
- Set
transform-origin correctly
- SVG: apply transforms on a
<g> wrapper with transform-box: fill-box; transform-origin: center
- Animations must be interruptible — respond to user input mid-animation
Typography
- Use
… (ellipsis character), not three periods ...
- Use curly quotes
" ", not straight quotes "
- Non-breaking spaces for units and key combos:
10 MB, ⌘ K, brand names
- Loading states end with
…: "Loading…", "Saving…"
- Apply
font-variant-numeric: tabular-nums to number columns and comparisons
- Use
text-wrap: balance or text-pretty on headings to prevent widows
Content Handling
- Text containers must handle long content:
truncate, line-clamp-*, or break-words
- Flex children need
min-w-0 to allow text truncation
- Handle empty states explicitly — never render broken UI for empty strings or arrays
- User-generated content: test with short, average, and very long inputs
Images
<img> requires explicit width and height to prevent Cumulative Layout Shift (CLS)
- Below-fold images:
loading="lazy"
- Above-fold critical images:
priority or fetchpriority="high"
Performance
- Lists with more than 50 items must be virtualized (
virtua, content-visibility: auto)
- No layout reads during render (
getBoundingClientRect, offsetHeight, offsetWidth, scrollTop)
- Batch DOM reads and writes; never interleave them
- Prefer uncontrolled inputs; controlled inputs must execute cheaply per keystroke
- Add
<link rel="preconnect"> for CDN and asset domains
- Critical fonts:
<link rel="preload" as="font"> with font-display: swap
Navigation and State
- URL must reflect application state — filters, tabs, pagination, and expanded panels belong in query params
- Links must use
<a> / <Link> to support Cmd/Ctrl+click and middle-click
- Deep-link all stateful UI — if a value uses
useState, consider URL sync via nuqs or similar
- Destructive actions require a confirmation modal or undo window — never execute immediately
Touch and Interaction
- Set
touch-action: manipulation to prevent double-tap zoom delay
- Set
-webkit-tap-highlight-color intentionally
- Set
overscroll-behavior: contain in modals, drawers, and sheets
- During drag: disable text selection; apply
inert on dragged elements
- Use
autoFocus sparingly — desktop only, single primary input; avoid on mobile
Safe Areas and Layout
- Full-bleed layouts need
env(safe-area-inset-*) for notch/island handling
- Prevent unwanted scrollbars:
overflow-x-hidden on containers; fix content overflow
- Use Flexbox or Grid for layout instead of JS measurement
Dark Mode and Theming
- Apply
color-scheme: dark to <html> for dark themes (fixes scrollbars and native inputs)
<meta name="theme-color"> must match the page background colour
- Native
<select>: set explicit background-color and color (required for Windows dark mode)
Locale and i18n
- Dates and times: use
Intl.DateTimeFormat — no hardcoded format strings
- Numbers and currency: use
Intl.NumberFormat — no hardcoded format strings
- Detect language via
Accept-Language / navigator.languages, not by IP address
Hydration Safety
- Controlled inputs with
value require onChange (or use defaultValue for uncontrolled)
- Date and time rendering: guard against server/client hydration mismatch
- Use
suppressHydrationWarning only where it is genuinely necessary and document why
Hover and Interactive States
- Buttons and links need a
hover: state for visual feedback
- Hover, active, and focus states must be more visually prominent than the resting state
Content and Copy
- Use active voice: "Install the CLI" not "The CLI will be installed"
- Title Case for headings and button labels (Chicago Manual of Style)
- Use numerals for counts: "8 deployments" not "eight deployments"
- Button labels must be specific: "Save API Key" not "Continue"
- Error messages must include a fix or next step — not just the problem
- Use second person; avoid first person ("you" not "I" or "we")
- Use
& over "and" where space is constrained
Anti-Patterns (Always Flag)
| Anti-Pattern |
Reason |
user-scalable=no or maximum-scale=1 |
Disables user zoom — accessibility violation |
onPaste + preventDefault |
Prevents users from pasting — never acceptable |
transition: all |
Causes unintended transitions and performance issues |
outline-none without focus-visible replacement |
Removes all keyboard focus visibility |
Inline onClick navigation without <a> |
Breaks Cmd/Ctrl+click, middle-click, and right-click |
<div> or <span> with click handlers |
Must be <button> or <a> |
<img> without width and height |
Causes layout shift (CLS) |
Large arrays .map() without virtualization |
Freezes the browser on large data sets |
| Form inputs without labels |
Screen readers cannot identify the field |
Icon buttons without aria-label |
Screen readers announce nothing meaningful |
| Hardcoded date or number formats |
Breaks for non-English locales |
autoFocus without justification |
Disruptive on mobile; confusing for screen reader users |
Output Format
Group findings by file. Use file:line format (clickable in VS Code and compatible editors).
Be terse — state the issue and location. Skip explanation unless the fix is non-obvious.
No preamble. No summary paragraph. Start directly with the first file heading.
## src/components/Button.tsx
src/components/Button.tsx:42 icon button missing aria-label
src/components/Button.tsx:18 input lacks label association
src/components/Button.tsx:55 animation missing prefers-reduced-motion guard
src/components/Button.tsx:67 transition: all → list properties explicitly
## src/components/Modal.tsx
src/components/Modal.tsx:12 missing overscroll-behavior: contain
src/components/Modal.tsx:34 "..." → "…" (ellipsis character)
src/components/Modal.tsx:89 <div onClick> → <button>
## src/components/Card.tsx
✓ pass
Examples
Example 1: Single file review
User: "Review src/components/LoginForm.tsx"
Agent: Fetches guidelines, reads the file, outputs findings grouped under ## src/components/LoginForm.tsx.
Example 2: Glob pattern review
User: "Audit all components in src/components/"
Agent: Fetches guidelines, reads all matched files, outputs findings grouped by file.
Example 3: Focused accessibility audit
User: "Check my UI for accessibility issues only"
Agent: Asks for the file or pattern, fetches guidelines, then applies only the Accessibility and Focus States rule categories.
Example 4: No files provided
User: "Review my UI"
Agent: Responds — "Which files or patterns would you like me to review? For example: src/components/*.tsx or src/app/page.tsx"
Notes
- This skill is agent-agnostic and works in Claude, Claude Code, VS Code, Cursor, Windsurf, Antigravity, and any environment supporting the Agent Skills standard.
- Always fetch the guidelines source URL before reviewing — never rely solely on the local reference above.
- If the fetch fails, inform the user and proceed using the local reference rules as a fallback, noting that the review may not reflect the latest guidelines.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: ecocee-skills-web-design-guidelines3description: Web Interface Guidelines Reviewer4---56# Web Interface Guidelines Reviewer78A comprehensive UI code review skill that audits frontend files against9established Web Interface Guidelines. Covers accessibility, performance,10typography, animation, forms, theming, and interaction patterns.1112Compatible with: Claude, Claude Code, VS Code agent extensions, Cursor,13Windsurf, and any agent that supports the Agent Skills standard.1415---1617## Behaviour18191. If the user provides a file path or glob pattern, begin the review immediately.202. If no files are specified, ask: "Which files or patterns would you like me to review?"213. Fetch the latest guidelines from the source URL before every review — never use a cached version.224. Read and parse all matched files.235. Check every file against all rule categories below.246. Output findings in the `file:line` format defined in the Output Format section.257. If a file passes all checks, output `✓ pass` — never skip it silently.2627---2829## Guidelines Source3031Always fetch the authoritative, up-to-date rules before reviewing:3233```34https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md35```3637Use a WebFetch or equivalent tool to retrieve this file fresh on every invocation.38The fetched content is the source of truth. Rules below are a local reference39and may lag behind the canonical source.4041---4243## Rule Categories (Local Reference)4445### Accessibility4647- Icon-only buttons require `aria-label`48- Form controls require `<label>` or `aria-label`49- Interactive elements require keyboard handlers (`onKeyDown` / `onKeyUp`)50- Use `<button>` for actions, `<a>` / `<Link>` for navigation — not `<div onClick>`51- Images require `alt`; decorative images use `alt=""`52- Decorative icons require `aria-hidden="true"`53- Async updates (toasts, validation messages) require `aria-live="polite"`54- Prefer semantic HTML over ARIA where a native element exists55- Headings must be hierarchical `<h1>`–`<h6>`; include a skip link for main content56- Heading anchors need `scroll-margin-top`5758### Focus States5960- All interactive elements need a visible focus indicator (`focus-visible:ring-*` or equivalent)61- Never use `outline-none` / `outline: none` without a replacement focus style62- Use `:focus-visible` over `:focus` to avoid showing ring on mouse click63- Use `:focus-within` for compound controls6465### Forms6667- Inputs need `autocomplete` and a meaningful `name` attribute68- Use correct `type` (`email`, `tel`, `url`, `number`) and `inputmode`69- Never block paste (`onPaste` + `preventDefault`)70- Labels must be clickable via `htmlFor` or by wrapping the control71- Disable spellcheck on emails, codes, and usernames (`spellCheck={false}`)72- Checkbox and radio label + control share a single hit target — no dead zones73- Submit button stays enabled until the request starts; show spinner during request74- Inline errors displayed next to the relevant field; focus first error on submit75- Placeholders end with `…` and show an example pattern76- Use `autocomplete="off"` on non-auth fields to avoid password manager conflicts77- Warn before navigation when unsaved changes exist (`beforeunload` or router guard)7879### Animation8081- Respect `prefers-reduced-motion` — provide a reduced variant or disable animation entirely82- Only animate `transform` and `opacity` (compositor-friendly properties)83- Never use `transition: all` — list properties explicitly84- Set `transform-origin` correctly85- SVG: apply transforms on a `<g>` wrapper with `transform-box: fill-box; transform-origin: center`86- Animations must be interruptible — respond to user input mid-animation8788### Typography8990- Use `…` (ellipsis character), not three periods `...`91- Use curly quotes `"` `"`, not straight quotes `"`92- Non-breaking spaces for units and key combos: `10 MB`, `⌘ K`, brand names93- Loading states end with `…`: `"Loading…"`, `"Saving…"`94- Apply `font-variant-numeric: tabular-nums` to number columns and comparisons95- Use `text-wrap: balance` or `text-pretty` on headings to prevent widows9697### Content Handling9899- Text containers must handle long content: `truncate`, `line-clamp-*`, or `break-words`100- Flex children need `min-w-0` to allow text truncation101- Handle empty states explicitly — never render broken UI for empty strings or arrays102- User-generated content: test with short, average, and very long inputs103104### Images105106- `<img>` requires explicit `width` and `height` to prevent Cumulative Layout Shift (CLS)107- Below-fold images: `loading="lazy"`108- Above-fold critical images: `priority` or `fetchpriority="high"`109110### Performance111112- Lists with more than 50 items must be virtualized (`virtua`, `content-visibility: auto`)113- No layout reads during render (`getBoundingClientRect`, `offsetHeight`, `offsetWidth`, `scrollTop`)114- Batch DOM reads and writes; never interleave them115- Prefer uncontrolled inputs; controlled inputs must execute cheaply per keystroke116- Add `<link rel="preconnect">` for CDN and asset domains117- Critical fonts: `<link rel="preload" as="font">` with `font-display: swap`118119### Navigation and State120121- URL must reflect application state — filters, tabs, pagination, and expanded panels belong in query params122- Links must use `<a>` / `<Link>` to support Cmd/Ctrl+click and middle-click123- Deep-link all stateful UI — if a value uses `useState`, consider URL sync via `nuqs` or similar124- Destructive actions require a confirmation modal or undo window — never execute immediately125126### Touch and Interaction127128- Set `touch-action: manipulation` to prevent double-tap zoom delay129- Set `-webkit-tap-highlight-color` intentionally130- Set `overscroll-behavior: contain` in modals, drawers, and sheets131- During drag: disable text selection; apply `inert` on dragged elements132- Use `autoFocus` sparingly — desktop only, single primary input; avoid on mobile133134### Safe Areas and Layout135136- Full-bleed layouts need `env(safe-area-inset-*)` for notch/island handling137- Prevent unwanted scrollbars: `overflow-x-hidden` on containers; fix content overflow138- Use Flexbox or Grid for layout instead of JS measurement139140### Dark Mode and Theming141142- Apply `color-scheme: dark` to `<html>` for dark themes (fixes scrollbars and native inputs)143- `<meta name="theme-color">` must match the page background colour144- Native `<select>`: set explicit `background-color` and `color` (required for Windows dark mode)145146### Locale and i18n147148- Dates and times: use `Intl.DateTimeFormat` — no hardcoded format strings149- Numbers and currency: use `Intl.NumberFormat` — no hardcoded format strings150- Detect language via `Accept-Language` / `navigator.languages`, not by IP address151152### Hydration Safety153154- Controlled inputs with `value` require `onChange` (or use `defaultValue` for uncontrolled)155- Date and time rendering: guard against server/client hydration mismatch156- Use `suppressHydrationWarning` only where it is genuinely necessary and document why157158### Hover and Interactive States159160- Buttons and links need a `hover:` state for visual feedback161- Hover, active, and focus states must be more visually prominent than the resting state162163### Content and Copy164165- Use active voice: "Install the CLI" not "The CLI will be installed"166- Title Case for headings and button labels (Chicago Manual of Style)167- Use numerals for counts: "8 deployments" not "eight deployments"168- Button labels must be specific: "Save API Key" not "Continue"169- Error messages must include a fix or next step — not just the problem170- Use second person; avoid first person ("you" not "I" or "we")171- Use `&` over "and" where space is constrained172173---174175## Anti-Patterns (Always Flag)176177| Anti-Pattern | Reason |178|---|---|179| `user-scalable=no` or `maximum-scale=1` | Disables user zoom — accessibility violation |180| `onPaste` + `preventDefault` | Prevents users from pasting — never acceptable |181| `transition: all` | Causes unintended transitions and performance issues |182| `outline-none` without focus-visible replacement | Removes all keyboard focus visibility |183| Inline `onClick` navigation without `<a>` | Breaks Cmd/Ctrl+click, middle-click, and right-click |184| `<div>` or `<span>` with click handlers | Must be `<button>` or `<a>` |185| `<img>` without `width` and `height` | Causes layout shift (CLS) |186| Large arrays `.map()` without virtualization | Freezes the browser on large data sets |187| Form inputs without labels | Screen readers cannot identify the field |188| Icon buttons without `aria-label` | Screen readers announce nothing meaningful |189| Hardcoded date or number formats | Breaks for non-English locales |190| `autoFocus` without justification | Disruptive on mobile; confusing for screen reader users |191192---193194## Output Format195196Group findings by file. Use `file:line` format (clickable in VS Code and compatible editors).197Be terse — state the issue and location. Skip explanation unless the fix is non-obvious.198No preamble. No summary paragraph. Start directly with the first file heading.199200```201## src/components/Button.tsx202203src/components/Button.tsx:42 icon button missing aria-label204src/components/Button.tsx:18 input lacks label association205src/components/Button.tsx:55 animation missing prefers-reduced-motion guard206src/components/Button.tsx:67 transition: all → list properties explicitly207208## src/components/Modal.tsx209210src/components/Modal.tsx:12 missing overscroll-behavior: contain211src/components/Modal.tsx:34 "..." → "…" (ellipsis character)212src/components/Modal.tsx:89 <div onClick> → <button>213214## src/components/Card.tsx215216✓ pass217```218219---220221## Examples222223### Example 1: Single file review224225User: "Review src/components/LoginForm.tsx"226Agent: Fetches guidelines, reads the file, outputs findings grouped under `## src/components/LoginForm.tsx`.227228### Example 2: Glob pattern review229230User: "Audit all components in src/components/"231Agent: Fetches guidelines, reads all matched files, outputs findings grouped by file.232233### Example 3: Focused accessibility audit234235User: "Check my UI for accessibility issues only"236Agent: Asks for the file or pattern, fetches guidelines, then applies only the Accessibility and Focus States rule categories.237238### Example 4: No files provided239240User: "Review my UI"241Agent: Responds — "Which files or patterns would you like me to review? For example: `src/components/*.tsx` or `src/app/page.tsx`"242243---244245## Notes246247- This skill is agent-agnostic and works in Claude, Claude Code, VS Code, Cursor, Windsurf, Antigravity, and any environment supporting the Agent Skills standard.248- Always fetch the guidelines source URL before reviewing — never rely solely on the local reference above.249- If the fetch fails, inform the user and proceed using the local reference rules as a fallback, noting that the review may not reflect the latest guidelines.250251---252> Converted and distributed by [TomeVault](https://tomevault.io/claim/ecocee) — claim your Tome and manage your conversions.253<!-- tomevault:4.0:skill_md:2026-04-16 -->