web-interface-guidelines
Original:🇺🇸 English
Translated
Use when designing, reviewing, or implementing web UIs and you need concrete MUST/SHOULD/NEVER rules for accessibility, interaction patterns, forms, layout, animation, performance, content, or visual design decisions.
4installs
Sourcedereknex/skills
Added on
NPX Install
npx skill4agent add dereknex/skills web-interface-guidelinesTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Web Interface Guidelines
Concise rules for building accessible, fast, delightful UIs. Use MUST/SHOULD/NEVER to guide decisions and reviews.
How to apply
- Prioritize MUST items first; NEVER items are hard constraints.
- When reviewing, scan each section and confirm every MUST is satisfied or consciously justified.
- If a guideline conflicts with product requirements, surface the conflict explicitly.
Quick reference
| Area | Top MUST checks |
|---|---|
| Keyboard | Full keyboard support per WAI-ARIA APG; visible focus rings; manage focus (trap/move/return) |
| Forms | No paste blocking; loading buttons keep label + spinner; inline errors + focus first error |
| Navigation | URL reflects state; links are links; back/forward restores scroll |
| Motion | Respect prefers-reduced-motion; animate transform/opacity only; animations interruptible |
| Layout | Respect safe areas; avoid unwanted scrollbars; verify mobile/laptop/ultra-wide |
| Content | Accurate labels; skip link + proper headings; resilient to long user content |
| Performance | Measure reliably; batch layout reads/writes; prevent CLS from images |
Interactions
- Keyboard
- MUST: Full keyboard support per WAI-ARIA APG patterns
- MUST: Visible focus rings (; group with
:focus-visible):focus-within - MUST: Manage focus (trap, move, and return) per APG patterns
- Targets & input
- MUST: Hit target >= 24px (mobile >= 44px). If visual < 24px, expand hit area.
- MUST: Mobile font-size >= 16px or set:
<input>html<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover"> - NEVER: Disable browser zoom
- MUST: to prevent double-tap zoom; set
touch-action: manipulationto match design-webkit-tap-highlight-color
- Inputs & forms (behavior)
- MUST: Hydration-safe inputs (no lost focus/value)
- NEVER: Block paste in
<input>/<textarea> - MUST: Loading buttons show spinner and keep original label
- MUST: Enter submits focused text input. In , Cmd/Ctrl+Enter submits; Enter adds newline.
<textarea> - MUST: Keep submit enabled until request starts; then disable, show spinner, use idempotency key
- MUST: Don’t block typing; accept free text and validate after
- MUST: Allow submitting incomplete forms to surface validation
- MUST: Errors inline next to fields; on submit, focus first error
- MUST: + meaningful
autocomplete; correctnameandtypeinputmode - SHOULD: Disable spellcheck for emails/codes/usernames
- SHOULD: Placeholders end with ellipsis and show example pattern (e.g., ,
+1 (123) 456-7890)sk-012345… - MUST: Warn on unsaved changes before navigation
- MUST: Compatible with password managers and 2FA; allow pasting one-time codes
- MUST: Trim values to handle text expansion trailing spaces
- MUST: No dead zones on checkboxes/radios; label+control share one generous hit target
- State & navigation
- MUST: URL reflects state (deep-link filters/tabs/pagination/expanded panels). Prefer libs like nuqs.
- MUST: Back/Forward restores scroll
- MUST: Links are links: use /
<a>for navigation (support Cmd/Ctrl/middle-click)<Link>
- Feedback
- SHOULD: Optimistic UI; reconcile on response; on failure show error and rollback or offer Undo
- MUST: Confirm destructive actions or provide Undo window
- MUST: Use polite for toasts/inline validation
aria-live - SHOULD: Ellipsis () for options that open follow-ups (e.g., "Rename…") and loading states (e.g., "Loading…")
…
- Touch/drag/scroll
- MUST: Design forgiving interactions (generous targets, clear affordances; avoid finickiness)
- MUST: Delay first tooltip in a group; subsequent peers no delay
- MUST: Intentional in modals/drawers
overscroll-behavior: contain - MUST: During drag, disable text selection and set on dragged element/containers
inert - MUST: No “dead-looking” interactive zones—if it looks clickable, it is
- Autofocus
- SHOULD: Autofocus on desktop when there’s a single primary input; rarely on mobile (avoid layout shift)
Animation
- MUST: Honor (provide reduced variant)
prefers-reduced-motion - SHOULD: Prefer CSS > Web Animations API > JS libraries
- MUST: Animate compositor-friendly props (,
transform); avoid layout/repaint props (opacity)top/left/width/height - SHOULD: Animate only to clarify cause/effect or add deliberate delight
- SHOULD: Choose easing to match the change (size/distance/trigger)
- MUST: Animations are interruptible and input-driven (avoid autoplay)
- MUST: Correct (motion starts where it "physically" should)
transform-origin
Layout
- SHOULD: Optical alignment; adjust by +/- 1px when perception beats geometry
- MUST: Deliberate alignment to grid/baseline/edges/optical centers (no accidental placement)
- SHOULD: Balance icon/text lockups (stroke/weight/size/spacing/color)
- MUST: Verify mobile, laptop, ultra-wide (simulate ultra-wide at 50% zoom)
- MUST: Respect safe areas (use )
env(safe-area-inset-*) - MUST: Avoid unwanted scrollbars; fix overflows
Content & accessibility
- SHOULD: Inline help first; tooltips last resort
- MUST: Skeletons mirror final content to avoid layout shift
- MUST: matches current context
<title> - MUST: No dead ends; always offer next step/recovery
- MUST: Design empty/sparse/dense/error states
- SHOULD: Curly quotes (“ ”); avoid widows/orphans
- MUST: Tabular numbers for comparisons (or a mono like Geist Mono)
font-variant-numeric: tabular-nums - MUST: Redundant status cues (not color-only); icons have text labels
- MUST: Don’t ship the schema—visuals may omit labels but accessible names still exist
- MUST: Use the ellipsis character
… - MUST: on headings for anchored links; include a “Skip to content” link; hierarchical
scroll-margin-top<h1–h6> - MUST: Resilient to user-generated content (short/avg/very long)
- MUST: Locale-aware dates/times/numbers/currency
- MUST: Accurate names (), decorative elements
aria-label, verify in the Accessibility Treearia-hidden - MUST: Icon-only buttons have descriptive
aria-label - MUST: Prefer native semantics (,
button,a,label) before ARIAtable - SHOULD: Right-clicking the nav logo surfaces brand assets
- MUST: Use non-breaking spaces to glue terms: ,
10 MB,⌘ + KVercel SDK
Performance
- SHOULD: Test iOS Low Power Mode and macOS Safari
- MUST: Measure reliably (disable extensions that skew runtime)
- MUST: Track and minimize re-renders (React DevTools/React Scan)
- MUST: Profile with CPU/network throttling
- MUST: Batch layout reads/writes; avoid unnecessary reflows/repaints
- MUST: Mutations () target < 500 ms
POST/PATCH/DELETE - SHOULD: Prefer uncontrolled inputs; make controlled loops cheap (keystroke cost)
- MUST: Virtualize large lists (e.g., virtua)
- MUST: Preload only above-the-fold images; lazy-load the rest
- MUST: Prevent CLS from images (explicit dimensions or reserved space)
Design
- SHOULD: Layered shadows (ambient + direct)
- SHOULD: Crisp edges via semi-transparent borders + shadows
- SHOULD: Nested radii: child <= parent; concentric
- SHOULD: Hue consistency: tint borders/shadows/text toward bg hue
- MUST: Accessible charts (color-blind-friendly palettes)
- MUST: Meet contrast (prefer APCA over WCAG 2)
- MUST: Increase contrast on /
:hover/:active:focus - SHOULD: Match browser UI to bg
- SHOULD: Avoid gradient banding (use masks when needed)
Example: loading submit button with inline error focus
tsx
type Props = {
pending: boolean;
errorId?: string;
};
export function SubmitButton({ pending, errorId }: Props) {
return (
<button
type="submit"
aria-describedby={errorId}
aria-busy={pending}
disabled={pending}
>
{pending ? (
<span aria-live="polite">
<span className="spinner" aria-hidden="true" />
Saving…
</span>
) : (
"Save"
)}
</button>
);
}Common mistakes
- Missing focus management in dialogs/drawers (no trap/return)
- Blocking paste in inputs or disabling zoom on mobile
- Loading states that replace labels instead of adding a spinner
- Links implemented as buttons (breaks Cmd/Ctrl/middle-click)
- Animating layout properties instead of /
transformopacity - Shipping icons without accessible labels or text alternatives
Red flags
- Keyboard users cannot reach or activate every interactive element
- Forms fail when autofill or password managers are used
- Scroll position is lost on back/forward
- CLS occurs when images load
- Motion plays for users who prefer reduced motion