Files
marketplaces/docs/ACCESSIBILITY_REPORT.md
sdarbinyan f5f431620e docs: add ACCESSIBILITY_REPORT.md for RC A11Y-01
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>
2026-07-24 09:19:18 +04:00

6.7 KiB
Raw Blame History

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-content landmark. 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-dialog coverage — they're custom, not app-dialog. Ported the confirmed-correct app-dialog pattern 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-activedescendant so the existing arrow-key navigation is actually announced to screen readers (previously silent).
  • Tabs — product tabs had role="tab" with no tablist/tabpanel wrapper; completed the pattern.
  • Forms — review-form errors now aria-describedby + role="alert"; aria-required on review textarea and delivery select.
  • Iconsapp-icon (shared, app-wide) claimed "decorative by default" in its own contract but never actually applied aria-hidden — fixed for real, affects every icon usage across the app.
  • Contrast--text-light measured 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-content landmark.
  • 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-primary token — 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-color token.
  • 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 announcementsapp-skeleton is aria-hidden by 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. Added role="status"/aria-live="polite"/aria-busy + sr-only text.
  • Table row headersscope="col" was already complete from the prior pass; added scope="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 through app-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-color fails 3:1 UI-component contrast in every theme (1.241.42:1) — pervasive token, hundreds of usages across the whole app.
  • --success-color/--warning-color/--error-color/--info-color fail 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, analytics lowStockProducts missing 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.