Web Interface Guidelines
Review files for compliance with Web Interface Guidelines.
How It Works
- Read the specified files (or prompt user for files/pattern)
- Check against all rules below
- Output findings in the terse
file:line format
Usage
When a user provides a file or pattern argument:
- Read the specified files
- Apply all rules from the guidelines below
- Output findings using the output format at the end
If no files specified, ask the user which files to review.
Rules
Accessibility
- Icon-only buttons need
aria-label
- Form controls need
<label> or aria-label
- Interactive elements need keyboard handlers (
onKeyDown/onKeyUp)
<button> for actions, <a>/<Link> for navigation (not <div onClick>)
- Images need
alt (or alt="" if decorative)
- Decorative icons need
aria-hidden="true"
- Async updates (toasts, validation) need
aria-live="polite"
- Use semantic HTML (
<button>, <a>, <label>, <table>) before ARIA
- Headings hierarchical
<h1>–<h6>; include skip link for main content
scroll-margin-top on heading anchors
Focus States
- Interactive elements need visible focus:
focus-visible:ring-* or equivalent
- Never
outline-none / outline: none without focus replacement
- Use
:focus-visible over :focus (avoid focus ring on click)
- Group focus with
:focus-within for compound controls
Forms
- Inputs need
autocomplete and meaningful name
- Use correct
type (email, tel, url, number) and inputmode
- Never block paste (
onPaste + preventDefault)
- Labels clickable (
htmlFor or wrapping control)
- Disable spellcheck on emails, codes, usernames (
spellCheck={false})
- Checkboxes/radios: label + control share single hit target (no dead zones)
- Submit button stays enabled until request starts; spinner during request
- Errors inline next to fields; focus first error on submit
- Placeholders end with
… and show example pattern
autocomplete="off" on non-auth fields to avoid password manager triggers
- Warn before navigation with unsaved changes (
beforeunload or router guard)
Animation
- Honor
prefers-reduced-motion (provide reduced variant or disable)
- Animate
transform/opacity only (compositor-friendly)
- Never
transition: all—list properties explicitly
- Set correct
transform-origin
- SVG: transforms on
<g> wrapper with transform-box: fill-box; transform-origin: center
- Animations interruptible—respond to user input mid-animation
Typography
… not ...
- Curly quotes
" " not straight "
- Non-breaking spaces:
10 MB, ⌘ K, brand names
- Loading states end with
…: "Loading…", "Saving…"
font-variant-numeric: tabular-nums for number columns/comparisons
- Use
text-wrap: balance or text-pretty on headings (prevents widows)
Content Handling
- Text containers handle long content:
truncate, line-clamp-*, or break-words
- Flex children need
min-w-0 to allow text truncation
- Handle empty states—don't render broken UI for empty strings/arrays
- User-generated content: anticipate short, average, and very long inputs
Images
<img> needs explicit width and height (prevents CLS)
- Below-fold images:
loading="lazy"
- Above-fold critical images:
priority or fetchpriority="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
- Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
- Add
<link rel="preconnect"> for CDN/asset domains
- Critical fonts:
<link rel="preload" as="font"> with font-display: swap
Navigation & State
- URL reflects state—filters, tabs, pagination, expanded panels in query params
- Links use
<a>/<Link> (Cmd/Ctrl+click, middle-click support)
- Deep-link all stateful UI (if uses
useState, consider URL sync via nuqs or similar)
- Destructive actions need confirmation modal or undo window—never immediate
Touch & Interaction
touch-action: manipulation (prevents double-tap zoom delay)
-webkit-tap-highlight-color set intentionally
overscroll-behavior: contain in modals/drawers/sheets
- During drag: disable text selection,
inert on dragged elements
autoFocus sparingly—desktop only, single primary input; avoid on mobile
Safe Areas & Layout
- Full-bleed layouts need
env(safe-area-inset-*) for notches
- Avoid unwanted scrollbars:
overflow-x-hidden on containers, fix content overflow
- Flex/grid over JS measurement for layout
Dark Mode & Theming
color-scheme: dark on <html> for dark themes (fixes scrollbar, inputs)
<meta name="theme-color"> matches page background
- Native
<select>: explicit background-color and color (Windows dark mode)
Locale & i18n
- Dates/times: use
Intl.DateTimeFormat not hardcoded formats
- Numbers/currency: use
Intl.NumberFormat not hardcoded formats
- Detect language via
Accept-Language / navigator.languages, not IP
Hydration Safety
- Inputs with
value need onChange (or use defaultValue for uncontrolled)
- Date/time rendering: guard against hydration mismatch (server vs client)
suppressHydrationWarning only where truly needed
Hover & Interactive States
- Buttons/links need
hover: state (visual feedback)
- Interactive states increase contrast: hover/active/focus more prominent than rest
Content & Copy
- Active voice: "Install the CLI" not "The CLI will be installed"
- Title Case for headings/buttons (Chicago style)
- Numerals for counts: "8 deployments" not "eight"
- Specific button labels: "Save API Key" not "Continue"
- Error messages include fix/next step, not just problem
- Second person; avoid first person
& over "and" where space-constrained
Anti-patterns (flag these)
user-scalable=no or maximum-scale=1 disabling zoom
onPaste with preventDefault
transition: all
outline-none without focus-visible replacement
- Inline
onClick navigation without <a>
<div> or <span> with click handlers (should be <button>)
- Images without dimensions
- Large arrays
.map() without virtualization
- Form inputs without labels
- Icon buttons without
aria-label
- Hardcoded date/number formats (use
Intl.*)
autoFocus without clear justification
Output Format
Group by file. Use file:line format (VS Code clickable). Terse findings.
## src/Button.tsx
src/Button.tsx:42 - icon button missing aria-label
src/Button.tsx:18 - input lacks label
src/Button.tsx:55 - animation missing prefers-reduced-motion
src/Button.tsx:67 - transition: all → list properties
## src/Modal.tsx
src/Modal.tsx:12 - missing overscroll-behavior: contain
src/Modal.tsx:34 - "..." → "…"
## src/Card.tsx
✓ pass
State issue + location. Skip explanation unless fix non-obvious. No preamble.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: web-design-guidelines-113description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices". Use when this capability is needed.4---56# Web Interface Guidelines78Review files for compliance with Web Interface Guidelines.910## How It Works11121. Read the specified files (or prompt user for files/pattern)132. Check against all rules below143. Output findings in the terse `file:line` format1516## Usage1718When a user provides a file or pattern argument:19201. Read the specified files212. Apply all rules from the guidelines below223. Output findings using the output format at the end2324If no files specified, ask the user which files to review.2526---2728## Rules2930### Accessibility3132- Icon-only buttons need `aria-label`33- Form controls need `<label>` or `aria-label`34- Interactive elements need keyboard handlers (`onKeyDown`/`onKeyUp`)35- `<button>` for actions, `<a>`/`<Link>` for navigation (not `<div onClick>`)36- Images need `alt` (or `alt=""` if decorative)37- Decorative icons need `aria-hidden="true"`38- Async updates (toasts, validation) need `aria-live="polite"`39- Use semantic HTML (`<button>`, `<a>`, `<label>`, `<table>`) before ARIA40- Headings hierarchical `<h1>`–`<h6>`; include skip link for main content41- `scroll-margin-top` on heading anchors4243### Focus States4445- Interactive elements need visible focus: `focus-visible:ring-*` or equivalent46- Never `outline-none` / `outline: none` without focus replacement47- Use `:focus-visible` over `:focus` (avoid focus ring on click)48- Group focus with `:focus-within` for compound controls4950### Forms5152- Inputs need `autocomplete` and meaningful `name`53- Use correct `type` (`email`, `tel`, `url`, `number`) and `inputmode`54- Never block paste (`onPaste` + `preventDefault`)55- Labels clickable (`htmlFor` or wrapping control)56- Disable spellcheck on emails, codes, usernames (`spellCheck={false}`)57- Checkboxes/radios: label + control share single hit target (no dead zones)58- Submit button stays enabled until request starts; spinner during request59- Errors inline next to fields; focus first error on submit60- Placeholders end with `…` and show example pattern61- `autocomplete="off"` on non-auth fields to avoid password manager triggers62- Warn before navigation with unsaved changes (`beforeunload` or router guard)6364### Animation6566- Honor `prefers-reduced-motion` (provide reduced variant or disable)67- Animate `transform`/`opacity` only (compositor-friendly)68- Never `transition: all`—list properties explicitly69- Set correct `transform-origin`70- SVG: transforms on `<g>` wrapper with `transform-box: fill-box; transform-origin: center`71- Animations interruptible—respond to user input mid-animation7273### Typography7475- `…` not `...`76- Curly quotes `"` `"` not straight `"`77- Non-breaking spaces: `10 MB`, `⌘ K`, brand names78- Loading states end with `…`: `"Loading…"`, `"Saving…"`79- `font-variant-numeric: tabular-nums` for number columns/comparisons80- Use `text-wrap: balance` or `text-pretty` on headings (prevents widows)8182### Content Handling8384- Text containers handle long content: `truncate`, `line-clamp-*`, or `break-words`85- Flex children need `min-w-0` to allow text truncation86- Handle empty states—don't render broken UI for empty strings/arrays87- User-generated content: anticipate short, average, and very long inputs8889### Images9091- `<img>` needs explicit `width` and `height` (prevents CLS)92- Below-fold images: `loading="lazy"`93- Above-fold critical images: `priority` or `fetchpriority="high"`9495### Performance9697- Large lists (>50 items): virtualize (`virtua`, `content-visibility: auto`)98- No layout reads in render (`getBoundingClientRect`, `offsetHeight`, `offsetWidth`, `scrollTop`)99- Batch DOM reads/writes; avoid interleaving100- Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke101- Add `<link rel="preconnect">` for CDN/asset domains102- Critical fonts: `<link rel="preload" as="font">` with `font-display: swap`103104### Navigation & State105106- URL reflects state—filters, tabs, pagination, expanded panels in query params107- Links use `<a>`/`<Link>` (Cmd/Ctrl+click, middle-click support)108- Deep-link all stateful UI (if uses `useState`, consider URL sync via nuqs or similar)109- Destructive actions need confirmation modal or undo window—never immediate110111### Touch & Interaction112113- `touch-action: manipulation` (prevents double-tap zoom delay)114- `-webkit-tap-highlight-color` set intentionally115- `overscroll-behavior: contain` in modals/drawers/sheets116- During drag: disable text selection, `inert` on dragged elements117- `autoFocus` sparingly—desktop only, single primary input; avoid on mobile118119### Safe Areas & Layout120121- Full-bleed layouts need `env(safe-area-inset-*)` for notches122- Avoid unwanted scrollbars: `overflow-x-hidden` on containers, fix content overflow123- Flex/grid over JS measurement for layout124125### Dark Mode & Theming126127- `color-scheme: dark` on `<html>` for dark themes (fixes scrollbar, inputs)128- `<meta name="theme-color">` matches page background129- Native `<select>`: explicit `background-color` and `color` (Windows dark mode)130131### Locale & i18n132133- Dates/times: use `Intl.DateTimeFormat` not hardcoded formats134- Numbers/currency: use `Intl.NumberFormat` not hardcoded formats135- Detect language via `Accept-Language` / `navigator.languages`, not IP136137### Hydration Safety138139- Inputs with `value` need `onChange` (or use `defaultValue` for uncontrolled)140- Date/time rendering: guard against hydration mismatch (server vs client)141- `suppressHydrationWarning` only where truly needed142143### Hover & Interactive States144145- Buttons/links need `hover:` state (visual feedback)146- Interactive states increase contrast: hover/active/focus more prominent than rest147148### Content & Copy149150- Active voice: "Install the CLI" not "The CLI will be installed"151- Title Case for headings/buttons (Chicago style)152- Numerals for counts: "8 deployments" not "eight"153- Specific button labels: "Save API Key" not "Continue"154- Error messages include fix/next step, not just problem155- Second person; avoid first person156- `&` over "and" where space-constrained157158### Anti-patterns (flag these)159160- `user-scalable=no` or `maximum-scale=1` disabling zoom161- `onPaste` with `preventDefault`162- `transition: all`163- `outline-none` without focus-visible replacement164- Inline `onClick` navigation without `<a>`165- `<div>` or `<span>` with click handlers (should be `<button>`)166- Images without dimensions167- Large arrays `.map()` without virtualization168- Form inputs without labels169- Icon buttons without `aria-label`170- Hardcoded date/number formats (use `Intl.*`)171- `autoFocus` without clear justification172173---174175## Output Format176177Group by file. Use `file:line` format (VS Code clickable). Terse findings.178179```text180## src/Button.tsx181182src/Button.tsx:42 - icon button missing aria-label183src/Button.tsx:18 - input lacks label184src/Button.tsx:55 - animation missing prefers-reduced-motion185src/Button.tsx:67 - transition: all → list properties186187## src/Modal.tsx188189src/Modal.tsx:12 - missing overscroll-behavior: contain190src/Modal.tsx:34 - "..." → "…"191192## src/Card.tsx193194✓ pass195```196197State issue + location. Skip explanation unless fix non-obvious. No preamble.198199---200> Converted and distributed by [TomeVault](https://tomevault.io/claim/hyaway) — claim your Tome and manage your conversions.201<!-- tomevault:4.0:skill_md:2026-04-11 -->