Files
atomic-design-poc/docs/ui-ux-audit.md
Edwin van den Houdt 64385999eb Add registratie wizard, BFF dashboard-view, contracts/value-objects, and architecture docs
Checkpoint of in-progress work: the registration wizard (address prefill,
DUO diploma lookup, policy questions), decision-DTO contracts, parse-don't-
validate value objects, infrastructure adapters, plus CLAUDE.md and the
architecture/ADR docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:23:52 +02:00

7.5 KiB
Raw Blame History

UI/UX audit — BIG-register wizard (Rijkshuisstijl alignment)

Phase A deliverable. Audits the registration wizard and the shared atoms/chrome it relies on against the project's design system (@rijkshuisstijl-community, the NL Design System Rijkshuisstijl theme — the canonical system here; CIBG's own DS is not installed) and WCAG 2.1 AA. Each finding maps to the token / component / pattern that resolves it. This is an alignment, not a redesign: fixes go through the token/theme layer and existing components; no new libraries, no restricted Rijksoverheid assets.

Scope: registratie wizard + shared atoms/chrome (intake/herregistratie inherit the shared fixes). Their own step copy/inline styles are out of scope.

Priority: H = blocks "professional/accessible" bar (a11y or broken token); M = visible inconsistency; L = polish.


1. Tokens vs. hardcoded values

The app imports RHC design tokens but the wizard/chrome were written with raw inline values (≈48 in wizard+chrome, ≈16 in atoms). RHC exposes a full token set we should map onto: spacing --rhc-space-max-{sm..5xl}, type --rhc-text-font-size-* / --rhc-text-font-weight-*, color --rhc-color-foreground-{default,subtle} / --rhc-color-{lintblauw,donkerblauw,cool-grey}-* / --rhc-color-wit, radius --rhc-border-radius-*.

# Pri Finding Resolves to
1.1 H var(--rhc-color-grijs-700) is referenced in 3 wizards but --rhc-color-grijs-* does not exist in the package → the "Stap X van Y" text falls back to the default color, not grey. --rhc-color-foreground-subtle
1.2 H site-header/site-footer set bg to var(--rhc-color-lintblauw-700,#154273) / …-900,#01689blintblauw-900 doesn't exist (only 50700), so the hex fallback renders. header --rhc-color-lintblauw-700; footer --rhc-color-donkerblauw-700; text --rhc-color-wit
1.3 M Raw spacing everywhere: 0.25/0.5/0.75/1/1.5/2/3rem as gap/margin/padding (≈30 occurrences). --rhc-space-max-{sm,md,lg,xl,2xl,3xl,5xl}
1.4 M Inconsistent form/content widths: 28rem, 30rem, 32rem, 64rem as raw max-width. app width tokens in styles.scss (--app-form-max, --app-content-max) mapped once
1.5 M spinner & skeleton hardcode greys/accent (#cad0d6, #e8ebee, #f3f5f6) and the spinner accent via bogus --rhc-color-lintblauw-700,#154273 fallback. --rhc-color-cool-grey-{200,300}, --rhc-color-lintblauw-700
1.6 L site-header hardcodes font-weight:700/400, font-size:0.9rem, opacity:0.85. --rhc-text-font-weight-{bold,regular}, --rhc-text-font-size-sm

2. Typography & heading hierarchy

# Pri Finding Resolves to
2.1 H Each page has one <h1> (page-shell) but the wizard steps have no <h2> — step title is a plain <p>. Screen-reader users get no step heading to navigate to. per-step <h2> via app-heading [level]="2"
2.2 M Type scale not applied to bespoke text (header wordmark uses raw sizes). --rhc-text-font-size-*, app-heading

3. Color & contrast

# Pri Finding Resolves to
3.1 H Because of 1.1/1.2 the actual rendered colors are partly accidental (default text color, hex fallbacks) — contrast is unverified. map to real tokens, then verify AA
3.2 M Palette discipline: confirm a single primary blue (lintblauw) + neutrals + status-only accents (alert types ok/info/warning/error already map to Utrecht alert variants). keep alert variants; route blues to lintblauw/donkerblauw tokens

4. Spacing & layout

# Pri Finding Resolves to
4.1 M Repeated inline idioms: display:flex;gap:0.5rem;margin-top:1rem (button rows, 6×), max-width:30rem (forms, 3×), margin:1rem 0 (summaries). utility classes .app-button-row, .app-form, .app-stack in styles.scss
4.2 L shell uses a custom --app-content-max:64rem defined inline. promote to the styles.scss token layer

5. Component reuse

# Pri Finding Resolves to
5.1 L intake-wizard review step uses bespoke <div><dt><dd> instead of app-data-row (out of scope here; note for later). app-data-row
5.2 M Button rows / form containers are ad-hoc inline layout rather than a shared idiom. utility classes (4.1)

6. Form, validation & status patterns

# Pri Finding Resolves to
6.1 H form-field renders the error with role="alert" but no id, and the projected input has no aria-describedby → error not programmatically linked. error id="${fieldId}-error"; input aria-describedby
6.2 H text-input never sets aria-invalid even when invalid() is true. [attr.aria-invalid]
6.3 H radio-group has role="radiogroup" but no accessible name and no invalid state. aria-labelledby="${name}-label", add invalid input → aria-invalid/aria-describedby
6.4 M Async states (app-async) render but aren't announced (no live region) — SR users miss loading→loaded/empty/error. wrap in aria-live="polite" + aria-busy
6.5 L No error-summary pattern; per-field inline errors only. Acceptable for short steps; revisit if steps grow. (defer)

7. Page chrome

# Pri Finding Resolves to
7.1 M No breadcrumb / location context in the portal chrome. new app-breadcrumb (.rhc-breadcrumb-nav), wired via page-shell
7.2 M Step progress is non-semantic text. new app-stepper (<ol>, aria-current="step")
7.3 L Skip-link uses left:-999px (works) and landmarks (header/main/footer) are correct. keep; tokenize offset

8. Copy & tone

# Pri Finding Resolves to
8.1 M Microcopy is functional but informal/uneven (labels, helper text, button text, the manual-diploma warning, the controle summary). formal, plain official Dutch; consistent with domain terms (registratie wizard + chrome only)

9. Accessibility (WCAG 2.1 AA) — consolidated

# Pri Finding Resolves to
9.1 H No focus management: after Next/Back focus stays on the button; SR/keyboard users aren't moved to the new step. move focus to the step <h2> (tabindex="-1") on cursor change
9.2 H Error/label/invalid association missing (6.16.3). as above
9.3 M Step changes & async states not announced (6.4). aria-live
9.4 M skeleton placeholders are announced as content. aria-hidden="true"
9.5 L No automated a11y in CI; only Storybook addon-a11y (axe) exists. add a11y parameters in preview.ts; keep manual keyboard/SR pass; no new deps

10. Responsive

# Pri Finding Resolves to
10.1 M Fixed rem widths and inline flex rows; verify reflow + ≥24px targets at narrow widths. token widths + flex-wrap on button rows; manual check

Tooling note

No eslint/stylelint/axe-core in the repo, and the prime directive forbids adding dependencies. Token compliance is enforced by a no-dep check:tokens npm script (greps touched templates for raw #hex and bare rem/px outside var(...)); accessibility uses the already-installed Storybook addon-a11y plus a manual keyboard/screen-reader pass.