Web Interface Guidelines
Review files for compliance: $ARGUMENTS
Read files, check against rules below. Output concise but terse. High signal-to-noise.
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.
1---2name: web-design-review3description: This skill should be used when user asks to "review my UI", "check accessibility", "audit design", "review UX", "check my site against best practices", or wants to review frontend code for Web Interface Guidelines compliance.4---5
6# Web Interface Guidelines
7
8Review files for compliance: $ARGUMENTS
9
10Read files, check against rules below. Output concise but terse. High signal-to-noise.
11
12## Rules
13
14### Accessibility
15
16- Icon-only buttons need `aria-label`
17- Form controls need `<label>` or `aria-label`
18- Interactive elements need keyboard handlers (`onKeyDown`/`onKeyUp`)
19- `<button>` for actions, `<a>`/`<Link>` for navigation (not `<div onClick>`)
20- Images need `alt` (or `alt=""` if decorative)
21- Decorative icons need `aria-hidden="true"`
22- Async updates (toasts, validation) need `aria-live="polite"`
23- Use semantic HTML (`<button>`, `<a>`, `<label>`, `<table>`) before ARIA
24- Headings hierarchical `<h1>`–`<h6>`; include skip link for main content
25- `scroll-margin-top` on heading anchors
26
27### Focus States
28
29- Interactive elements need visible focus: `focus-visible:ring-*` or equivalent
30- Never `outline-none` / `outline: none` without focus replacement
31- Use `:focus-visible` over `:focus` (avoid focus ring on click)
32- Group focus with `:focus-within` for compound controls
33
34### Forms
35
36- Inputs need `autocomplete` and meaningful `name`
37- Use correct `type` (`email`, `tel`, `url`, `number`) and `inputmode`
38- Never block paste (`onPaste` + `preventDefault`)
39- Labels clickable (`htmlFor` or wrapping control)
40- Disable spellcheck on emails, codes, usernames (`spellCheck={false}`)
41- Checkboxes/radios: label + control share single hit target (no dead zones)
42- Submit button stays enabled until request starts; spinner during request
43- Errors inline next to fields; focus first error on submit
44- Placeholders end with `…` and show example pattern
45- `autocomplete="off"` on non-auth fields to avoid password manager triggers
46- Warn before navigation with unsaved changes (`beforeunload` or router guard)
47
48### Animation
49
50- Honor `prefers-reduced-motion` (provide reduced variant or disable)
51- Animate `transform`/`opacity` only (compositor-friendly)
52- Never `transition: all`—list properties explicitly
53- Set correct `transform-origin`
54- SVG: transforms on `<g>` wrapper with `transform-box: fill-box; transform-origin: center`
55- Animations interruptible—respond to user input mid-animation
56
57### Typography
58
59- `…` not `...`
60- Curly quotes `"` `"` not straight `"`
61- Non-breaking spaces: `10 MB`, `⌘ K`, brand names
62- Loading states end with `…`: `"Loading…"`, `"Saving…"`
63- `font-variant-numeric: tabular-nums` for number columns/comparisons
64- Use `text-wrap: balance` or `text-pretty` on headings (prevents widows)
65
66### Content Handling
67
68- Text containers handle long content: `truncate`, `line-clamp-*`, or `break-words`
69- Flex children need `min-w-0` to allow text truncation
70- Handle empty states—don't render broken UI for empty strings/arrays
71- User-generated content: anticipate short, average, and very long inputs
72
73### Images
74
75- `<img>` needs explicit `width` and `height` (prevents CLS)
76- Below-fold images: `loading="lazy"`
77- Above-fold critical images: `priority` or `fetchpriority="high"`
78
79### Performance
80
81- Large lists (>50 items): virtualize (`virtua`, `content-visibility: auto`)
82- No layout reads in render (`getBoundingClientRect`, `offsetHeight`, `offsetWidth`, `scrollTop`)
83- Batch DOM reads/writes; avoid interleaving
84- Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
85- Add `<link rel="preconnect">` for CDN/asset domains
86- Critical fonts: `<link rel="preload" as="font">` with `font-display: swap`
87
88### Navigation & State
89
90- URL reflects state—filters, tabs, pagination, expanded panels in query params
91- Links use `<a>`/`<Link>` (Cmd/Ctrl+click, middle-click support)
92- Deep-link all stateful UI (if uses `useState`, consider URL sync via nuqs or similar)
93- Destructive actions need confirmation modal or undo window—never immediate
94
95### Touch & Interaction
96
97- `touch-action: manipulation` (prevents double-tap zoom delay)
98- `-webkit-tap-highlight-color` set intentionally
99- `overscroll-behavior: contain` in modals/drawers/sheets
100- During drag: disable text selection, `inert` on dragged elements
101- `autoFocus` sparingly—desktop only, single primary input; avoid on mobile
102
103### Safe Areas & Layout
104
105- Full-bleed layouts need `env(safe-area-inset-*)` for notches
106- Avoid unwanted scrollbars: `overflow-x-hidden` on containers, fix content overflow
107- Flex/grid over JS measurement for layout
108
109### Dark Mode & Theming
110
111- `color-scheme: dark` on `<html>` for dark themes (fixes scrollbar, inputs)
112- `<meta name="theme-color">` matches page background
113- Native `<select>`: explicit `background-color` and `color` (Windows dark mode)
114
115### Locale & i18n
116
117- Dates/times: use `Intl.DateTimeFormat` not hardcoded formats
118- Numbers/currency: use `Intl.NumberFormat` not hardcoded formats
119- Detect language via `Accept-Language` / `navigator.languages`, not IP
120
121### Hydration Safety
122
123- Inputs with `value` need `onChange` (or use `defaultValue` for uncontrolled)
124- Date/time rendering: guard against hydration mismatch (server vs client)
125- `suppressHydrationWarning` only where truly needed
126
127### Hover & Interactive States
128
129- Buttons/links need `hover:` state (visual feedback)
130- Interactive states increase contrast: hover/active/focus more prominent than rest
131
132### Content & Copy
133
134- Active voice: "Install the CLI" not "The CLI will be installed"
135- Title Case for headings/buttons (Chicago style)
136- Numerals for counts: "8 deployments" not "eight"
137- Specific button labels: "Save API Key" not "Continue"
138- Error messages include fix/next step, not just problem
139- Second person; avoid first person
140- `&` over "and" where space-constrained
141
142### Anti-patterns (flag these)
143
144- `user-scalable=no` or `maximum-scale=1` disabling zoom
145- `onPaste` with `preventDefault`
146- `transition: all`
147- `outline-none` without focus-visible replacement
148- Inline `onClick` navigation without `<a>`
149- `<div>` or `<span>` with click handlers (should be `<button>`)
150- Images without dimensions
151- Large arrays `.map()` without virtualization
152- Form inputs without labels
153- Icon buttons without `aria-label`
154- Hardcoded date/number formats (use `Intl.*`)
155- `autoFocus` without clear justification
156
157## Output Format
158
159Group by file. Use `file:line` format (VS Code clickable). Terse findings.
160
161```text
162## src/Button.tsx
163
164src/Button.tsx:42 - icon button missing aria-label
165src/Button.tsx:18 - input lacks label
166src/Button.tsx:55 - animation missing prefers-reduced-motion
167src/Button.tsx:67 - transition: all → list properties
168
169## src/Modal.tsx
170
171src/Modal.tsx:12 - missing overscroll-behavior: contain
172src/Modal.tsx:34 - "..." → "…"
173
174## src/Card.tsx
175
176✓ pass
177```
178
179State issue + location. Skip explanation unless fix non-obvious. No preamble.