Consolidates the 3 WCAG 2.1 AA audit commits (storefront, builder, backoffice): skip links, keyboard-operable DnD fallbacks, dialog focus-trap fixes, contrast fixes, form labeling, live-region announcements, combobox/tablist ARIA. Flags remaining brand-color contrast failures needing theme-owner sign-off, not fixed unilaterally. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.7 KiB
Accessibility Report — RC A11Y-01
WCAG 2.1 AA audit + fixes across the whole application: Storefront, Builder (Project Editor), Backoffice (Admin). No redesign, no layout changes, no route/business-logic changes. Three sequential commits on branch B2B (not pushed):
| Commit | Scope |
|---|---|
fb1afb7 |
Storefront |
a03260e |
Builder |
565fd9b |
Backoffice |
npm run build verified green after every commit. npx tsc --noEmit clean throughout.
This audit goes deeper than the prior composition pass (docs/UI-COMPOSITION-REVIEW.md — skeletons/empty-states/scope="col") into categories that pass didn't cover: skip links, keyboard-operable drag-and-drop, dialog focus management, color contrast ratios, form label association, live-region announcements, and combobox/tablist ARIA patterns.
Fixes by area
Storefront (fb1afb7)
- Skip link — didn't exist anywhere in the app. Added as the first focusable element (
app.html), targeting a new#main-contentlandmark. Single most commonly-missing WCAG 2.4.1 fix, present nowhere before this. - Keyboard/focus traps — header mobile menu kept its items tabbable/screen-reader-reachable while visually collapsed; fixed via
visibility+ delayed transition. Header's search input had no keyboard activation path. - Dialog accessibility — cart's custom payment/bank-payment modals had no focus-trap, Escape handling, or return-focus, despite prior docs assuming
app-dialogcoverage — they're custom, notapp-dialog. Ported the confirmed-correctapp-dialogpattern directly onto them. - Screen-reader announcements — payment status screens (creating/waiting/success/error/timeout) got
role="status"/role="alert"+aria-live. - Search combobox — added
role="combobox"/aria-autocomplete/aria-controls/aria-activedescendantso the existing arrow-key navigation is actually announced to screen readers (previously silent). - Tabs — product tabs had
role="tab"with notablist/tabpanelwrapper; completed the pattern. - Forms — review-form errors now
aria-describedby+role="alert";aria-requiredon review textarea and delivery select. - Icons —
app-icon(shared, app-wide) claimed "decorative by default" in its own contract but never actually appliedaria-hidden— fixed for real, affects every icon usage across the app. - Contrast —
--text-lightmeasured 3.39:1 (dexar theme) / 2.54:1 (lavero/novo) against the 4.5:1 requirement. Switched the 2 in-scope usages to--text-secondary(7.56:1 / 4.55:1).
Builder (a03260e)
- Skip link — Builder routes render outside the storefront app-shell entirely (bare
<router-outlet>), so the storefront fix didn't cover it. Added separately with its own#builder-main-contentlandmark. - Keyboard-operable drag-and-drop (WCAG 2.1.1) — Homepage section's block list and Footer section's columns/links use Angular CDK drag-drop with zero keyboard equivalent. Added move-up/move-down button fallbacks (Navigation and Widgets sections already had this from an earlier sprint).
- Undefined
--color-primarytoken — same bug class as the prior composition pass, missed there: 7 usages across 3 files silently fell back to hardcoded hex, never responding to tenant theming. Remapped to the real--primary-colortoken. - Forms — color-picker's
<input type="color">swatches (8 instances) had no accessible name; new-locale input relied on placeholder text alone (invisible to screen readers once a value is typed). - Screen-reader announcements — save-bar status/draft-restored notice and media-picker upload errors had no
aria-live/role.
Backoffice (565fd9b)
- Sidebar nav mislabeled —
<nav aria-label>reused the "Dashboard" translation key, so the entire admin sidebar announced itself as "Dashboard" to screen readers regardless of which section a user was in. New dedicated label. - Categories tree drag-and-drop (WCAG 2.1.1) — native HTML5 DnD reorder had no keyboard path; arrow keys only expand/collapse/select. Added move-up/move-down buttons per row, boundary-disabled, reusing the existing
reorder()facade method (no logic change). - Screen-reader loading announcements —
app-skeletonisaria-hiddenby design (correct for visual-only use), but 9 list pages (Products, Categories, Customers, Orders, Transactions, Users, Reviews, Monitoring, Analytics) had no accompanying live-region text, so screen-reader users got total silence during loads. Addedrole="status"/aria-live="polite"/aria-busy+ sr-only text. - Table row headers —
scope="col"was already complete from the prior pass; addedscope="row"to the primary identifying cell on 9 tables (product/category/customer name, order/transaction number, etc.) with matching CSS resets so the shared table's header styling doesn't visually leak onto them. - Dialogs, forms,
scope="col"— already correct across the board (all route throughapp-dialog/app-form-field), confirmed not re-touched.
Deliberately not fixed (flagged for a design-decision follow-up)
Failing color contrast that is a genuine brand/semantic color, not a bug — fixing these means changing what the palette looks like, which needs sign-off from whoever owns the theme, not an accessibility pass's unilateral call:
--border-colorfails 3:1 UI-component contrast in every theme (1.24–1.42:1) — pervasive token, hundreds of usages across the whole app.--success-color/--warning-color/--error-color/--info-colorfail 4.5:1 when used as plain text-on-white in a handful of places.- Builder save-bar's warning/error/info text-on-white — same category.
Other flagged items:
- Locale-tabs' partial tablist pattern (no roving-tabindex) — accepted precedent across all 3 surfaces, not fixed in any of them.
- No toast/success-error notification system exists anywhere in the app (backoffice save/delete has nothing to announce — a feature gap, not an accessibility regression of existing UI).
- Dashboard's per-card mini-skeletons — would need a page-level live region rather than per-widget, deferred.
- A handful of already-known partial-widget gaps carried from
docs/UI-COMPOSITION-REVIEW.md(monitoring events table, notifications dropdown, analyticslowStockProductsmissing skeleton) — pre-flagged, not newly found, not re-litigated here.
Verification
tsc --noEmit and npm run build green after all three commits. No live browser/screen-reader session available this session — recommend a manual pass with an actual screen reader (NVDA/VoiceOver) and automated tooling (axe-core/Lighthouse a11y score) against a deployed build before the client demo referenced in docs/FRONTEND-ROADMAP.md, since static-analysis ARIA correctness doesn't guarantee real-world screen-reader UX.