Accessibility Pitfalls¶
These Are Legal Liability
Since June 28, 2025, the European Accessibility Act makes these mistakes legally actionable. Fines can reach 100,000 euros or 4% of annual revenue. But beyond the law — these mistakes exclude real people from using the software GE builds.
Pitfall 1: ARIA Overuse¶
The mistake: Adding ARIA attributes to everything, thinking more ARIA means more accessible.
The reality: The first rule of ARIA is do not use ARIA. Use native HTML elements. They are accessible by default. ARIA is a repair tool for when native HTML is insufficient.
The damage ARIA overuse causes:
| Problem | Example | Consequence |
|---|---|---|
| Redundant roles | <button role="button"> |
Confuses some screen readers |
| Incorrect roles | <div role="button"> without keyboard handling |
Looks like a button, does not act like one |
| Missing states | role="checkbox" without aria-checked |
Screen reader cannot report state |
| Conflicting info | aria-label="Submit" on a button that says "Send" |
Screen reader says "Submit" but visual users see "Send" |
| Overriding semantics | <nav role="navigation"> |
Redundant, but some developers add more |
GE prevention:
- Use native HTML elements first:
<button>,<a>,<input>,<select> - ARIA is only for custom widgets without native equivalents
- Code review checks for unnecessary ARIA
- eslint-plugin-jsx-a11y flags common ARIA mistakes
The decision tree:
Can a native HTML element do this?
├── Yes → Use the native element. No ARIA needed.
└── No → Is there a WAI-ARIA authoring practice for this widget?
├── Yes → Follow it exactly.
└── No → Reconsider the design. If a widget has no established
pattern, users will not know how to interact with it.
Pitfall 2: "Works with Mouse" Bias¶
The mistake: Building and testing exclusively with a mouse. If it clicks, it works. Ship it.
Who is excluded:
- Users with motor disabilities who use keyboards or switches
- Power users who prefer keyboard navigation
- Screen reader users who navigate via keyboard
- Users with temporary injuries (broken arm, RSI)
Common keyboard failures:
| Failure | Example |
|---|---|
| Click-only interactions | Dropdown opens on hover, no keyboard trigger |
| Missing focus styles | Tab key moves focus but nothing visible changes |
| Keyboard traps | Focus enters a widget and cannot leave |
| No skip links | Keyboard user must tab through 50 nav items on every page |
| Custom scrolling | Mouse wheel works, keyboard scroll does not |
| Drag-and-drop only | No keyboard alternative for reordering |
GE prevention:
- All interactive elements must be keyboard accessible
- Focus indicators are visible (2px minimum, 3:1 contrast)
- Manual keyboard testing is part of the review checklist
- Antje writes keyboard navigation test cases in TDD
Pitfall 3: Color-Only Information¶
The mistake: Using color as the sole means of conveying information, status, or meaning.
Who is excluded:
- 8% of men and 0.5% of women have color vision deficiency
- Users viewing screens in direct sunlight
- Users on monochrome displays or in high contrast mode
- Users who have customized their color settings
Common violations:
| Violation | Fix |
|---|---|
| Red text = error, black text = valid | Add error icon + "Error:" prefix |
| Green dot = online, red dot = offline | Add text label "Online"/"Offline" |
| Chart with color-coded lines only | Add patterns, markers, or labels |
| Required fields marked with red asterisk only | Add "(required)" text |
| Links distinguished by color only | Add underline or other visual indicator |
GE prevention:
- Color is always paired with text, icons, or patterns
- Alexander's design system enforces this at the component level
- Automated contrast checking in CI/CD
- Manual review includes grayscale check
Pitfall 4: Missing Skip Links¶
The mistake: No mechanism to skip repetitive navigation content.
The impact: A keyboard or screen reader user must tab through the entire navigation menu on every single page before reaching the main content. On a site with 20 navigation links, that is 20 tab presses before they can read anything.
GE prevention:
<!-- First focusable element on the page -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Navigation here -->
<main id="main-content">
<!-- Page content -->
</main>
Skip links are visually hidden by default but become visible on focus. They are the first element in the tab order.
For complex pages, multiple skip links may be needed:
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#search" class="skip-link">Skip to search</a>
<a href="#footer" class="skip-link">Skip to footer</a>
Pitfall 5: Custom Components Without Keyboard Support¶
The mistake: Building custom UI components (dropdowns, modals, tabs, date pickers, carousels) that only work with a mouse.
Why it happens: Native HTML form elements look plain.
Designers want custom styling. Developers rebuild from <div> elements.
The rebuilt component looks right but loses all native accessibility.
What native elements provide for free:
| Feature | Native | Custom (must implement yourself) |
|---|---|---|
| Keyboard navigation | Built-in | Must handle keyDown events |
| Focus management | Built-in | Must manage tabindex |
| Screen reader support | Built-in | Must add ARIA roles and states |
| Form validation | Built-in | Must implement and announce |
| Touch support | Built-in | Must handle touch events |
GE prevention:
- Prefer native elements with CSS styling
- When custom components are necessary, follow WAI-ARIA Authoring Practices exactly
- Every custom component must handle: Tab, Shift+Tab, Enter, Space, Escape, Arrow keys (as appropriate for the widget type)
- Antje writes keyboard interaction tests before implementation
Pitfall 6: "We Will Add Accessibility Later"¶
The mistake: Building the feature first, planning to add accessibility in a future sprint.
Why it never works:
- Accessibility retrofitting costs 10-100x more than building accessible
- The backlog grows faster than the remediation capacity
- Structural issues (wrong HTML elements, missing landmarks) require rewriting, not patching
- "Later" never comes — there is always a higher-priority feature
The math:
Build accessible from line 1: +10% effort during development
Retrofit accessibility after: +100-500% effort, plus rewrite risk
Fix after a lawsuit: Unlimited effort, plus legal costs
GE prevention:
- Accessibility is in the definition of done
- An inaccessible feature does not pass code review
- There is no "accessibility sprint" because every sprint includes accessibility
- Julian blocks deployment if WCAG AA is not met
Pitfall 7: Testing Only with Automated Tools¶
The mistake: Running axe-core or Lighthouse, getting a passing score, and declaring the site accessible.
What automated tools catch (~30-40%):
- Missing alt text
- Low color contrast
- Missing form labels
- Invalid ARIA attributes
- Missing document language
- Duplicate IDs
What automated tools miss (~60-70%):
- Logical tab order (tools cannot know what is "logical")
- Meaningful alt text (tools check existence, not quality)
- Keyboard traps (require interaction to detect)
- Focus management in dynamic content
- Screen reader announcement quality
- Cognitive accessibility (is the content understandable?)
- Touch target adequacy in real-world context
- Content reflow at 200% zoom
- Context-appropriate ARIA usage
GE prevention:
- Automated testing is the baseline, not the standard
- Manual keyboard testing on every feature
- Screen reader testing on key user flows
- Marta and Iwona verify accessibility in code review
- Quarterly manual accessibility audit on production
The 100% Lighthouse score trap:
A Lighthouse accessibility score of 100 means the automated checks passed. It does not mean the site is accessible. Lighthouse tests approximately 50 rules. WCAG 2.2 AA has 86 success criteria, many of which require human judgment.
Pitfall 8: Focus Management in SPAs¶
The mistake: In single-page applications, when navigation changes the view without a page reload, focus stays on the element that triggered the navigation. The user does not know the content has changed.
The problem: In a traditional multi-page site, a new page load resets focus to the top. Screen readers announce the new page title. SPAs break this contract.
Common SPA focus failures:
| Scenario | Failure | Fix |
|---|---|---|
| Route change | Focus stays on nav link | Move focus to main heading or use aria-live |
| Content loaded | New content appears, focus unchanged | Announce with aria-live="polite" |
| Item deleted | Focus lost (element gone) | Move focus to next item or parent |
| Modal opened | Focus stays behind modal | Move focus to modal, trap within |
| Infinite scroll | New items load, no announcement | Announce "X more items loaded" |
| Form submission | Success message appears off-screen | Move focus to success message or use alert role |
GE prevention:
- SPA routing includes focus management
- Route changes move focus to the main heading (
<h1>) - Dynamic content updates use
aria-liveregions - Deleting items moves focus to a predictable location
- All modals trap focus and restore on close
Implementation pattern:
// On route change in SPA
useEffect(() => {
const mainHeading = document.querySelector('h1');
if (mainHeading) {
mainHeading.setAttribute('tabindex', '-1');
mainHeading.focus();
}
// Announce page title to screen readers
document.title = `${pageTitle} | App Name`;
}, [location]);
Pitfall 9: Inaccessible Error Handling¶
The mistake: Displaying error messages that are only visible (not announced) or only indicated by color change.
Common error handling failures:
| Failure | Impact |
|---|---|
| Error shown above form, not linked to field | Screen reader user does not know which field has error |
| Error shown only as red border | Color-blind users do not see the error |
| Error disappears after timeout | Slow readers miss the message |
| Validation on blur only | Keyboard-only users miss errors on previous fields |
| Error summary not focusable | Screen reader users cannot find the error list |
GE prevention:
<!-- Error summary at top of form, focusable -->
<div role="alert" tabindex="-1" id="error-summary">
<h2>There are 2 errors in this form</h2>
<ul>
<li><a href="#email">Email address is required</a></li>
<li><a href="#password">Password must be at least 8 characters</a></li>
</ul>
</div>
<!-- Inline error linked to field -->
<label for="email">Email address</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
/>
<p id="email-error" class="error">
<span aria-hidden="true">⚠</span>
Email address is required
</p>
Pitfall 10: Accessibility Overlays¶
The mistake: Installing a JavaScript overlay widget (AccessiBe, UserWay, AudioEye, etc.) instead of fixing the underlying code.
Why overlays fail:
- They do not fix the source code — they add a broken layer on top
- They can interfere with real assistive technology
- They have been cited in ADA lawsuits as insufficient
- They can break existing accessible features
- They create a false sense of compliance
- The National Federation of the Blind has publicly opposed overlays
GE position: Overlays are never used. Accessibility is built into the code. There are no shortcuts.
Quick Reference: Agent Checklist¶
Before submitting code with UI components:
- [ ] Semantic HTML used (not divs as buttons or spans as links)
- [ ] ARIA used only when native HTML is insufficient
- [ ] All interactive elements keyboard accessible
- [ ] Focus indicators visible (2px minimum, 3:1 contrast)
- [ ] Color is not the only means of conveying information
- [ ] Form fields have visible labels (not just placeholders)
- [ ] Error messages linked to fields and announced
- [ ] Images have appropriate alt text
- [ ] Dynamic content changes announced to screen readers
- [ ] Skip links present
- [ ] axe-core test included for new components
- [ ] Manually tested with keyboard navigation
Further Reading¶
- Accessibility-First Philosophy — Why accessibility comes first
- Development Workflow — Accessibility at every pipeline stage
- WCAG 2.2 Quick Reference (W3C) — Full success criteria
- WAI-ARIA Authoring Practices — Correct widget patterns