Ir al contenido

ADR-013 — Accessibility (WCAG 2.1 AA Baseline)

ADR-013 — Accessibility (WCAG 2.1 AA Baseline)

Sección titulada «ADR-013 — Accessibility (WCAG 2.1 AA Baseline)»

Accepted

Coveris is used in institutional healthcare environments (hospitals, ministries) where accessibility is both a legal requirement and a professional obligation (Section 508, EU Web Accessibility Directive, Argentine Ley 26.653). Before this decision the codebase had organic a11y habits — route announcements, skip links in shells, some ARIA attributes — but no formal standard and no enforcement. PrimeNG provides built-in WCAG 2.1 AA compliance for its components (keyboard navigation, ARIA attributes, screen reader support), but structural issues must be handled by the developer: semantic HTML landmarks, skip links, ARIA labels on custom elements, and CSS media query support for user preferences. The SAKAI template was audited and found to have minimal accessibility — no landmarks, no skip links, no labels on icon-only buttons — and Coveris must not inherit these gaps.

Target: WCAG 2.1 Level AA. All pages and components must meet WCAG 2.1 Level AA. PrimeNG’s built-in a11y ([[adr-012-design-system|ADR-012]]) is leveraged as-is; the rules below cover what PrimeNG cannot provide.

Semantic HTML and structural landmarks. Use <header>, <nav>, <main>, <aside>, <footer>, <section> instead of <div> with classes. ARIA roles fill only gaps semantic HTML cannot. Every shell includes <a href="#main-content" class="kdx-skip-link"> as the first focusable element; <main id="main-content" tabindex="-1"> is the target. The root AppComponent maintains an aria-live="assertive" region that announces page titles on navigation (already implemented in app.ts). Active route links use [attr.aria-current]="isActive ? 'page' : null", not CSS-only class changes. All <i class="pi pi-*"> decorative icons adjacent to text labels carry aria-hidden="true"; icon-only buttons carry an explicit ariaLabel.

PrimeNG component labeling. Every <p-table> carries aria-label or aria-labelledby; header cells use scope="col". Every <p-tree> carries aria-label or aria-labelledby. Buttons that open <p-dialog> bind aria-expanded and aria-controls. Avatar/icon buttons that open <p-menu> carry ariaLabel and ariaHaspopup="menu". Every form input has an associated <label> — visible or .sr-only — never placeholder alone.

Custom interactive components. Theme/color picker buttons use role="radio" within a role="radiogroup", with aria-checked reflecting selection and aria-label naming each color. The sidebar toggle binds aria-expanded to sidebar open state and aria-controls to the sidebar element id. Loading spinners are wrapped in role="status" with an sr-only label.

CSS adaptations. Global :focus-visible outline is 2px solid at 2px offset; :prefers-contrast: more increases it to 3px. @media (prefers-reduced-motion: reduce) disables all animations and transitions globally — components must not override this. Information is never conveyed through color alone; it is always paired with text, icons, or patterns. <p-tag> with severity satisfies this by rendering both color and label text.

Enforcement. Accessibility audits are run after each milestone using Lighthouse (accessibility score) and keyboard-only navigation. There is no automated axe-core integration in MVP scope.

  • Screen reader users can navigate using landmarks, skip links, and route announcements.
  • Keyboard-only users can operate all controls: sidebar toggle, color pickers, menus, tables.
  • Users with motion sensitivity or high-contrast needs get appropriate CSS adaptations.
  • Every new component requires explicit a11y attributes, increasing template verbosity.
  • Custom interactive widgets need explicit WAI-ARIA role management beyond what PrimeNG provides.
  • [[adr-009-a-frontend-testing-strategy|ADR-009-a]] enforces dark: class prohibition via static analysis, relying on this ADR’s rule that PrimeNG tokens handle dark mode, not Tailwind dark variants.