UI / UX Architecture
Implementation-level standards for accessible, consistent, responsive frontends. Implements the what and how; framework-specific where lives in react-architect and nextjs-architect. Component recipes, token templates, and testing setup in RECIPES.md. Pinned dependencies in STACK.md.
1. Accessibility floor — WCAG 2.2 AA
Non-negotiable. Every shipped component meets WCAG 2.2 Level AA; AAA where reasonable.
- Semantic HTML first. A
<button>is a button; a<div onClick>is a bug.<nav>,<main>,<article>,<aside>,<header>,<footer>mark landmarks. - Every interactive element is keyboard-operable.
Tabto focus,Enter/Spaceto activate,Escapeto dismiss, arrow keys inside composite widgets. No mouse-only behavior. - Visible focus indicator on every focusable element. Don't
outline: nonewithout replacing it. Tailwind:focus-visible:ring-2 focus-visible:ring-offset-2. - Color contrast ≥ 4.5:1 for normal text, ≥ 3:1 for large text and UI components. Enforced by
axe-corein CI; rejected at build. - Form labels. Every
<input>has a<label htmlFor>; placeholder text is not a label. - ARIA only when semantic HTML can't say it.
aria-labelfor icon-only buttons,aria-describedbyfor inline help,role="alert"for live announcements. Don't sprinklerole="button"— write<button>. prefers-reduced-motionrespected — Tailwind:motion-safe:/motion-reduce:variants. Disable parallax, autoplay, large transitions for users who request it.
2. Component primitives — Radix + Tailwind + shadcn/ui
Don't reinvent dialogs, dropdowns, popovers, comboboxes. Modern accessibility is hard; let primitives do the keyboard/ARIA work.
- Radix UI — headless, unstyled, accessible primitives. Focus management, keyboard nav, ARIA wiring all done.
- Tailwind CSS 4 — utility-first styling on top of Radix. Variables-based theme system, design tokens via CSS custom properties.
- shadcn/ui — copy-paste component recipes (Radix + Tailwind). Components live in your repo, not as a dep; you own and adapt them.
- Why not MUI / Mantine / Chakra? Great but opinionated; harder to evolve a custom design system; ship more JS. Radix + Tailwind gives full control with smaller bundles.
Wrapper example (Dialog) in RECIPES §1.
3. Design tokens
Centralize every visual decision as a token. Components reference tokens; tokens evolve in one place.
- Semantic over literal names.
--color-primarynot--color-blue-500. Lets you change the palette without rewriting every component. - OKLCH for color. Perceptually uniform, future-proof, supports wider gamuts.
- Dark mode via CSS variables — flip a few tokens, every component follows.
- Spacing scale based on 4 px (or 8 px). Don't introduce one-off values; reuse
--spacing-N. - Type scale centralized in tokens too (
--text-sm,--text-base).
Full @theme template in RECIPES §2.
4. Responsive — mobile-first, container queries when shape matters
- Mobile-first. Default styles are mobile;
md:,lg:add desktop overrides. - Container queries (
@container) when a component's layout depends on its container size, not the viewport. New in Tailwind 4 — use them for components in narrow sidebars and wide pages. - Breakpoints sparingly:
sm,md,lg,xl,2xl. Don't invent new ones per project. - Touch targets ≥ 44×44 px on mobile. WCAG 2.2 AA mandates 24×24 minimum but 44×44 is the modern usable size.
- Fluid typography —
clamp(1rem, 0.9rem + 0.5vw, 1.25rem)scales smoothly without breakpoint jumps. - Test on real devices. Browser DevTools mobile mode is a poor proxy for actual phones. Minimum: one iPhone, one Android.
5. The four required states — loading, error, empty, success
Every UI surface that touches data has four states. Build all four; don't pretend the success path is enough.
- Loading — skeletons for content, spinners for "button doing something",
aria-busy="true", no flashes under 300 ms. - Error — plain language, retry button, correlation ID visible, no stack traces, different shape per error class (network/auth/validation).
- Empty — first-time empty differs from filtered empty; action always present.
- Success — tables semantic, cursor pagination, refetch indicator.
Full shape contracts in RECIPES §3.
6. Forms
- Native HTML semantics.
<form>,<label>,<input>with right types (email,tel,number). autocompleteon every relevant field — browsers and password managers depend on them.- Inline validation on blur, not on every keystroke. Submit-time validation is the final gate.
- Error placement: below the input, connected via
aria-describedby— screen readers announce automatically. - Submit button disabled while pending — use
aria-disabled="true"(notdisabled, which removes it from tab order). - Inline success feedback — "Saved" with a checkmark for 2 s, then fade. Don't toast critical confirmations away.
7. Motion
prefers-reduced-motion: reducerespected. Tailwindmotion-safe:transition-*.- Functional motion only — confirmation feedback, spatial relationships, state changes that wouldn't be perceptible otherwise.
- No autoplaying video / animation without user opt-in.
- Easing:
ease-outfor entrances,ease-infor exits,ease-in-outfor in-place transitions. - Duration 100–300 ms for UI animation; 0 ms when
prefers-reduced-motion: reduce.
8. Icons
- One icon set per project. Lucide is the modern default.
aria-hidden="true"on decorative icons.aria-labelon icon-only buttons.- SVG sprites or per-icon components, never icon fonts. Fonts cause FOIT and a11y issues.
- Don't mix icon sets — visual inconsistency reads as instability.
9. Internationalization (when in scope)
<html lang="...">always set, even for English-only apps.- All copy through a translation function if i18n is on the roadmap —
t("user.greeting")even before there's a second language. - Directionality: RTL via
dir="rtl"and CSS logical properties (margin-inline-startnotmargin-left). Tailwind 4's logical-property utilities cover this. - Date / number / currency formatting via
Intl.DateTimeFormat,Intl.NumberFormat.
10. Testing accessibility
axe-coreintegrated into Vitest tests + Playwright e2e. Zero WCAG 2.2 AA violations before merge.- Manual keyboard pass on every new component — tab through, activate every control, no mouse.
- Screen reader pass on critical flows — NVDA or VoiceOver.
- Color contrast checker for every design token decision.
- Lighthouse a11y score ≥ 95 in CI. Lighthouse misses things axe catches and vice versa — run both.
Test scaffolds (Vitest + Playwright) in RECIPES §5.
11. Design system maturity ladder
Where a project sits informs how much investment is justified. Five levels from ad-hoc Tailwind to a documented system with visual regression tests — full ladder in RECIPES §4.
- Start at Level 1 (shared primitives in
components/ui/) for any non-throwaway project. - Climb to Level 2 (centralized tokens) when more than one developer touches styles.
- Level 4 (Storybook + Chromatic) earns its place when there's a real design system team or many product teams consuming the same components.
12. Cross-skill ties
- react-architect — client component patterns, hooks, state. This ski