# Web interface

> The craft floor for anything you ship in a browser: the polish that separates merely working from genuinely feeling right.

> Source: [Vercel Web Interface Guidelines](https://vercel.com/design/guidelines), curated to what matters most for daily-use work tools. Add their `AGENTS.md` version to your product repo so agents apply these during generation, not as cleanup.

## Interactions

- Keyboard works everywhere; follow WAI-ARIA patterns. Visible focus via `:focus-visible` (A11Y-2).
- Hit targets ≥ 24px desktop, 44px mobile; expand the hit area if the visual is smaller (A11Y-4).
- Input font size ≥ 16px on mobile (prevents iOS zoom). Never disable browser zoom or paste.
- URL as state: filters, tabs, pagination, expanded panels are deep-linkable; Back/Forward restores scroll.
- Optimistic updates where success is likely; on failure, explain and roll back or offer Undo.
- Links are links: `<a>`/`<Link>` for navigation, never `<button>` or `<div>`, so Cmd-click works.
- Buttons show loading state and keep their label; add show-delay (~200ms) and minimum visible time (~400ms) to avoid flicker.

## Forms

- Every control has a label; activating the label focuses the control (A11Y-3).
- Enter submits. Don't block typing, don't block paste, don't pre-disable submit; let validation explain.
- Errors appear next to their fields; on submit, focus the first error (CNT-1 anatomy).
- Set `autocomplete`, correct `type`/`inputmode`; placeholders show example values and end with an ellipsis.

## Performance

- Mutations complete in < 500ms perceived; show progress beyond that.
- No image-caused layout shift: explicit dimensions, reserved space. Preload critical fonts.
- Virtualise large lists; data tables and member lists get long.
- Tabular numbers (`font-variant-numeric: tabular-nums`) wherever values are compared in columns.

## Craft details

- Optical alignment over geometric when perception beats geometry; everything aligns with something.
- Nested radii: child ≤ parent, concentric. Interactions increase contrast (hover/active/focus above rest).
- Honour `prefers-reduced-motion` (A11Y-5); animate `transform`/`opacity` only; never `transition: all` (MOT-1, SLP-8).
- Curly quotes, real ellipsis character, non-breaking spaces in glued terms ("Q3&nbsp;report").

## Related

### Agent skill

- `/dx-harness:dx-design-pattern`: Reviews page structure: hierarchy, density, alignment, and pattern fit. Proposes ranked fixes.

[All skills](/harness/skills)

### In the catalogue

- [LAY-1](/standards/catalog/lay-1) (L2): Layout uses the product's declared column grid and gutter scale; ad-hoc column counts and off-scale gutters are findings — N/A where no grid is declared
- [LAY-2](/standards/catalog/lay-2) (L1): Layout reflows to a single column with no loss at 320 CSS px (WCAG 2.2 SC 1.4.10); reading order and controls hold at 360/768/1280
- [LAY-3](/standards/catalog/lay-3) (L2): A surface maps to a known page template (workspace view, form, flow step, dashboard, settings, empty state, onboarding) rather than an ad-hoc shell
- [LAY-4](/standards/catalog/lay-4) (L2): Body-text columns cap at a comfortable measure — target ~66ch, never above 80ch (WCAG 1.4.8); full-bleed running text is a finding
- [LAY-5](/standards/catalog/lay-5) (L2): Density suits the task — neither cramped for data entry nor padded for scanning; extreme outliers in either direction are findings
- [LAY-6](/standards/catalog/lay-6) (L2): Shared edges align; optical alignment is used where geometry misleads
- [LAY-7](/standards/catalog/lay-7) (L2): The page has one primary focal region and its visual reading order matches the task's priority order
- [SLP-4](/standards/catalog/slp-4) (L1): No nested cards; flatten with spacing, typography, and dividers
- [SLP-5](/standards/catalog/slp-5) (L2): No icon-tile-above-heading feature-card template; no identical card grids as default layout
- [SLP-10](/standards/catalog/slp-10) (L1): Complex multi-section tasks get a page, not a modal
- [SLP-11](/standards/catalog/slp-11) (L2): A card is only for an interactive unit (clickable, selectable, draggable); static content is grouped with spacing, type, and dividers
