DOMAIN:ACCESSIBILITY¶
OWNER: julian
UPDATED: 2026-03-18
SCOPE: all client-facing web applications
LEGAL:EAA¶
STANDARD: European Accessibility Act — Directive (EU) 2019/882
STATUS: enforceable since June 28, 2025
TECHNICAL_STANDARD: EN 301 549 v3.2.1
EXEMPTION: microenterprises (<10 employees AND <EUR 2M turnover) — most Dutch SME clients do NOT qualify
PENALTIES: up to EUR 100,000 or 4% annual revenue (varies by Member State)
TRANSITION: existing services until June 28, 2030
NEXT: EN 301 549 v4.1.1 with WCAG 2.2 expected 2026
COVERED_SERVICES:
- e-commerce websites and mobile apps
- banking and financial services
- telecommunications
- e-books and e-readers
- audio-visual media
- transport (ticketing, real-time info)
- all SaaS accessible to EU consumers (B2C and B2B with end users)
EN301549 — Beyond WCAG¶
CRITICAL: meeting WCAG 2.1 AA alone does NOT ensure EN 301 549 compliance
ADDITIONAL_REQUIREMENTS:
CHECK: software interoperability with assistive technologies (Ch. 11) — platform accessibility services
CHECK: biometric auth alternatives — if fingerprint/face ID used, must provide non-biometric option
CHECK: video player accessibility — specific requirements for embedded media
CHECK: real-time communication accessibility — VoIP, video calling, real-time text
CHECK: mobile application criteria (Table A.2) — NOT covered by WCAG at all
CHECK: documentation and support accessibility — help text, manuals, customer support
CHECK: functional performance statements (Clause 4) — without vision, limited vision, without hearing, limited manipulation
WCAG:PERCEIVABLE¶
1.1:TEXT_ALTERNATIVES¶
CHECK: all non-text content has text alternative
CHECK: decorative images have empty alt (alt="") — NOT missing alt attribute
CHECK: complex images (charts, diagrams) have long description
CHECK: form inputs have properly associated labels
1.2:TIME_BASED_MEDIA¶
CHECK: video has captions (pre-recorded and live)
CHECK: audio-only has transcript
CHECK: video-only has audio description or transcript
1.3:ADAPTABLE¶
CHECK: structure via proper HTML semantics (headings, lists, tables)
CHECK: reading order meaningful when CSS removed
CHECK: instructions don't rely solely on sensory characteristics (shape, color, size, position)
1.4:DISTINGUISHABLE¶
CHECK: color not sole means of conveying info
CHECK: contrast 4.5:1 normal text, 3:1 large text (18pt or 14pt bold)
CHECK: text resizable to 200% without content loss
CHECK: images of text avoided
CHECK: 1.4.10 reflow — content reflows at 320px without horizontal scroll
CHECK: 1.4.11 non-text contrast — UI components and graphics 3:1
CHECK: 1.4.13 content on hover/focus — tooltips dismissible, hoverable, persistent
WCAG:OPERABLE¶
2.1:KEYBOARD¶
CHECK: all functionality via keyboard
CHECK: no keyboard traps
CHECK: character key shortcuts can be remapped or disabled
2.2:ENOUGH_TIME¶
CHECK: time limits adjustable (turn off, extend, or 20+ hours)
CHECK: moving/blinking content can be paused/stopped/hidden
2.3:SEIZURES¶
CHECK: nothing flashes >3 times/second
2.4:NAVIGABLE¶
CHECK: skip navigation link present
CHECK: page titles descriptive
CHECK: focus order logical
CHECK: link purpose clear from text (or context)
CHECK: multiple ways to find pages (nav, search, sitemap)
CHECK: headings and labels descriptive
CHECK: focus visible — keyboard focus indicator present and clear
2.5:INPUT_MODALITIES¶
CHECK: no multipoint or path-based gesture requirement without alternative
CHECK: pointer cancellation — down-event doesn't trigger action
CHECK: label in name — visible label matches accessible name
WCAG:UNDERSTANDABLE¶
3.1:READABLE¶
CHECK: lang attribute on html element
CHECK: lang attribute on parts with different language
3.2:PREDICTABLE¶
CHECK: no unexpected context change on focus
CHECK: no unexpected context change on input
CHECK: consistent navigation across pages
CHECK: consistent identification of functional components
3.3:INPUT_ASSISTANCE¶
CHECK: errors identified and described in text
CHECK: labels or instructions for user input
CHECK: error suggestions provided
CHECK: error prevention for legal/financial (reversible, checked, confirmed)
WCAG:ROBUST¶
4.1:COMPATIBLE¶
CHECK: no duplicate IDs
CHECK: all UI components have programmatic name and role
CHECK: 4.1.3 status messages — dynamic updates via aria-live regions
WCAG_2.2_ADDITIONS (October 2023)¶
2.4.11 FOCUS_NOT_OBSCURED (AA): focused component not entirely hidden by sticky headers/modals
2.5.7 DRAGGING_MOVEMENTS (AA): drag-and-drop has single-pointer alternative
2.5.8 TARGET_SIZE_MINIMUM (AA): touch targets 24x24 CSS pixels minimum
3.2.6 CONSISTENT_HELP (A): help mechanism in consistent location
3.3.7 REDUNDANT_ENTRY (A): don't re-ask previously provided info
3.3.8 ACCESSIBLE_AUTH (AA): no cognitive function tests for login (CAPTCHAs need alternatives)
TESTING¶
AUTOMATED (catches <40%)¶
RUN: axe-core in CI — @axe-core/playwright or cypress-axe
RUN: lighthouse accessibility audit
RUN: pa11y in CI pipeline
CRITICAL: automated pass != accessible
MANUAL:KEYBOARD (catches ~30% more)¶
TEST: tab through entire application
TEST: can you reach everything?
TEST: is focus order logical?
TEST: can you operate all interactive elements?
TEST: are there keyboard traps?
TEST: is focus visible at all times?
MANUAL:SCREEN_READER (catches remaining)¶
TEST_WITH: NVDA (Windows, free) — primary
TEST_WITH: VoiceOver (macOS/iOS) — use Safari
TEST: all interactive elements announced correctly?
TEST: dynamic content announced?
TEST: forms labeled?
TEST: route changes announce?
TEST: images described?
MANUAL:VISUAL¶
TEST: color contrast (TPGi Colour Contrast Analyser)
TEST: text resize to 200% — content reflows?
TEST: info conveyed by color alone?
TEST: touch targets 24x24 CSS pixels?
FREQUENCY¶
EVERY_PR: automated axe-core
EVERY_SPRINT: keyboard navigation on new features
PRE_RELEASE: full manual audit (screen reader + keyboard + visual)
QUARTERLY: comprehensive review with real users
ARIA_RULES¶
RULE_1: don't use ARIA if native HTML works
BAD: <div role="button" tabindex="0" onclick="submit()">Submit</div>
GOOD: <button type="submit">Submit</button>
WHEN_ARIA_NEEDED:
- live regions for dynamic content (aria-live="polite")
- custom widgets without native HTML equivalent (tabs, tree views)
- describing relationships (aria-describedby, aria-labelledby)
- indicating state (aria-expanded, aria-selected, aria-current)
COMMON_MISTAKES:
- aria-label on non-interactive elements
- duplicate/conflicting names (visible "Search", aria-label "Find")
- role="presentation" on meaningful content
- missing required ARIA properties (role="tab" without aria-selected)
- overuse — adding ARIA everywhere breaks AT understanding
SPA_ACCESSIBILITY (Next.js, Nuxt)¶
ROUTE_CHANGES¶
PROBLEM: screen readers don't announce page changes in SPAs
FIX: move focus to main content or page heading on route change
FIX_ALT: aria-live region to announce new page title
NOTE: Next.js has built-in route announcer — verify with target screen readers
DYNAMIC_CONTENT¶
- AJAX/fetch content must be announced
- aria-live="polite" for non-urgent updates
- aria-live="assertive" only for critical alerts
- loading states: announce "Loading..." and completion
FOCUS_MANAGEMENT¶
- modal close → return focus to triggering element
- item deletion → focus to next item or parent
- form submission → focus to success/error message
- navigation → focus to main content area
OVERLAY_SOLUTIONS — NEVER RECOMMEND¶
AccessiBe, UserWay, AudioEye = condemned by disability community (800+ signatories at overlayfactsheet.com)
DO_NOT_ACHIEVE: WCAG conformance
OFTEN_WORSE: interfere with assistive technologies
NOT_LEGAL_DEFENSE: multiple lawsuits against overlay users
POSITION: never recommend. always fix source code.
READ_ALSO: domains/security/tools.md (accessibility tools), domains/eu-regulation/index.md
ADDITIONAL_PAGES¶
- EAA Requirements — European Accessibility Act scope, deadlines, penalties, GE vs client responsibility, documentation
- WCAG 2.2 — WCAG 2.2 AA requirements mapped to dev tasks, all new 2.2 criteria detailed
- Testing Methodology — Automated testing (axe-core, Lighthouse, Pa11y), manual testing, screen reader protocols
- Component Patterns — Accessible forms, modals, tabs, accordions, tables, carousels, toasts, date pickers
- Pitfalls — ARIA overuse, focus traps, skip links, dynamic content, color-only indicators, keyboard traps