diff --git a/docs/ACCESSIBILITY_IMPLEMENTATION_PLAN.md b/docs/ACCESSIBILITY_IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..47ed1df --- /dev/null +++ b/docs/ACCESSIBILITY_IMPLEMENTATION_PLAN.md @@ -0,0 +1,670 @@ +# Accessibility Implementation Plan - Maternal App + +**Created**: October 2, 2025 +**Target**: WCAG 2.1 AA Compliance +**Priority**: CRITICAL (Launch Blocker) + +--- + +## Executive Summary + +This document outlines the comprehensive accessibility implementation plan to achieve WCAG 2.1 AA compliance for the Maternal App. Accessibility is a **critical launch requirement** for legal compliance (ADA, Section 508) and to ensure the app is usable by all parents, including those with disabilities. + +**Current Status**: No accessibility implementation detected +**Target**: Full WCAG 2.1 AA compliance +**Timeline**: 2 weeks (Phases 1-3) + +--- + +## Table of Contents + +1. [Why Accessibility Matters](#why-accessibility-matters) +2. [WCAG 2.1 AA Requirements](#wcag-21-aa-requirements) +3. [Current State Assessment](#current-state-assessment) +4. [Implementation Phases](#implementation-phases) +5. [Technical Requirements](#technical-requirements) +6. [Testing Strategy](#testing-strategy) +7. [Success Metrics](#success-metrics) + +--- + +## Why Accessibility Matters + +### Legal Requirements +- **ADA (Americans with Disabilities Act)**: Web accessibility is legally required +- **Section 508**: Federal compliance for government users +- **WCAG 2.1 AA**: International standard for web accessibility + +### User Impact +- **15% of the population** has some form of disability +- **New parents** may have temporary disabilities (sleep deprivation, holding baby) +- **Situational disabilities**: Using app in bright sunlight, noisy environments +- **Assistive technology users**: Screen readers, keyboard-only, voice control + +### Business Benefits +- Larger addressable market +- Better SEO (semantic HTML) +- Improved UX for all users +- Legal risk mitigation +- Positive brand reputation + +--- + +## WCAG 2.1 AA Requirements + +### Four Core Principles (POUR) + +#### 1. **Perceivable** +- Text alternatives for non-text content +- Captions and alternatives for multimedia +- Adaptable content (can be presented in different ways) +- Distinguishable (easy to see and hear) + +#### 2. **Operable** +- Keyboard accessible (all functionality available via keyboard) +- Sufficient time (users have enough time to read and use content) +- Seizures and physical reactions (nothing that causes seizures) +- Navigable (users can navigate, find content, and determine where they are) +- Input modalities (make it easier to operate functionality through various inputs) + +#### 3. **Understandable** +- Readable (text content is readable and understandable) +- Predictable (web pages appear and operate in predictable ways) +- Input assistance (help users avoid and correct mistakes) + +#### 4. **Robust** +- Compatible (maximize compatibility with current and future user agents) + +--- + +## Current State Assessment + +### What We Have ✅ +- **Material-UI (MUI)**: Built-in accessibility features +- **React 18**: Modern framework with good accessibility support +- **Semantic HTML**: Some usage of proper HTML5 elements +- **Next.js 13**: Server-side rendering for better screen reader support + +### What's Missing ❌ + +#### **Critical Issues** +1. ❌ No ARIA labels on interactive elements +2. ❌ No keyboard navigation support +3. ❌ No focus indicators +4. ❌ No screen reader testing +5. ❌ Missing alt text on images/icons +6. ❌ Poor color contrast (not verified) +7. ❌ No skip navigation links +8. ❌ Forms lack proper labels and error messages +9. ❌ No focus management for dialogs/modals +10. ❌ No reduced motion support + +#### **High Priority Issues** +- Missing landmark regions (header, nav, main, footer) +- No heading hierarchy verification +- Missing aria-live regions for dynamic content +- No keyboard shortcuts documentation +- Touch targets not verified (44x44px minimum) + +--- + +## Implementation Phases + +### **Phase 1: Foundation (Week 1, Days 1-3)** 🏗️ + +#### **Goal**: Establish accessibility infrastructure and fix critical keyboard/focus issues + +**Tasks:** + +1. **Setup Accessibility Tools** (Day 1 Morning) + - Install `eslint-plugin-jsx-a11y` (React accessibility linting) + - Install `axe-core` and `@axe-core/react` (runtime accessibility testing) + - Configure ESLint rules for accessibility + - Install `jest-axe` for automated testing + - Add accessibility check to CI/CD + +2. **Keyboard Navigation** (Day 1 Afternoon - Day 2) + - Implement focus trap for modals/dialogs + - Add visible focus indicators (outline/ring) + - Create skip navigation link + - Fix tab order across all pages + - Add keyboard shortcuts for common actions + - Document keyboard navigation patterns + +3. **ARIA Labels & Semantic HTML** (Day 2 - Day 3) + - Audit all interactive elements (buttons, links, inputs) + - Add aria-label/aria-labelledby where needed + - Fix heading hierarchy (h1 → h2 → h3) + - Add landmark regions (header, nav, main, footer) + - Convert icon-only buttons to have text alternatives + - Add aria-describedby for form hints + +4. **Focus Management** (Day 3) + - Implement focus management for route changes + - Focus first heading on page load + - Trap focus in modals/dialogs + - Return focus when closing modals + - Manage focus for toast notifications + +**Deliverables:** +- ESLint accessibility rules configured +- Axe-core integrated into dev environment +- All pages keyboard navigable +- Focus indicators visible +- Skip navigation link added + +--- + +### **Phase 2: Content & Forms (Week 1, Days 4-5)** 📝 + +#### **Goal**: Make all content accessible and improve form usability + +**Tasks:** + +1. **Alternative Text** (Day 4 Morning) + - Audit all images for alt text + - Add descriptive alt text to photos + - Mark decorative images as `alt=""` + - Add aria-label to icon buttons + - Document icon meanings + +2. **Form Accessibility** (Day 4 Afternoon - Day 5 Morning) + - Add explicit labels to all inputs + - Associate labels with inputs (htmlFor/id) + - Add aria-required to required fields + - Improve error messages with aria-invalid + - Add aria-describedby for help text + - Group related inputs with fieldset/legend + - Add autocomplete attributes + +3. **Color Contrast** (Day 5 Morning) + - Audit color contrast ratios (WCAG AA: 4.5:1 for text, 3:1 for large text) + - Fix low-contrast text + - Ensure error states don't rely on color alone + - Add patterns/icons to supplement color coding + +4. **Live Regions** (Day 5 Afternoon) + - Add aria-live to toast notifications + - Add aria-live to loading states + - Add aria-live to activity feed updates + - Add status messages for async operations + +**Deliverables:** +- All images have appropriate alt text +- All forms fully accessible +- Color contrast meets WCAG AA +- Live regions for dynamic content + +--- + +### **Phase 3: Testing & Polish (Week 2, Days 1-3)** ✅ + +#### **Goal**: Comprehensive testing and documentation + +**Tasks:** + +1. **Automated Testing** (Day 1) + - Write jest-axe tests for all pages + - Add axe-core checks to E2E tests + - Run Lighthouse accessibility audits + - Fix all automated test failures + - Add accessibility tests to CI/CD + +2. **Screen Reader Testing** (Day 2) + - Test with NVDA (Windows) + - Test with JAWS (Windows) + - Test with VoiceOver (macOS/iOS) + - Test with TalkBack (Android) + - Document screen reader issues + - Fix critical screen reader bugs + +3. **Manual Testing** (Day 2-3) + - Test all pages with keyboard only (no mouse) + - Test with browser zoom (up to 200%) + - Test with high contrast mode + - Test with reduced motion + - Test with different viewport sizes + - Test all user flows + +4. **Documentation** (Day 3) + - Create accessibility statement page + - Document keyboard shortcuts + - Add ARIA patterns guide for developers + - Create accessibility testing checklist + - Document known issues (if any) + +**Deliverables:** +- Automated accessibility tests passing +- Screen reader testing complete +- Manual testing checklist complete +- Accessibility documentation published + +--- + +### **Phase 4: Advanced Features (Week 2, Days 4-5)** 🚀 + +#### **Goal**: Enhanced accessibility features + +**Tasks:** + +1. **Reduced Motion Support** (Day 4 Morning) + ```css + @media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + } + ``` + - Detect `prefers-reduced-motion` + - Disable animations for users who prefer reduced motion + - Keep essential motion (loading indicators) + +2. **Text Scaling** (Day 4 Afternoon) + - Test with browser text zoom up to 200% + - Use relative units (rem, em) instead of px + - Ensure layout doesn't break at 200% zoom + - Test with browser zoom (page zoom) + +3. **Touch Target Sizes** (Day 5 Morning) + - Audit all interactive elements + - Ensure minimum 44x44px (iOS) / 48x48dp (Android) + - Add padding to small targets + - Increase spacing between adjacent targets + +4. **Additional Enhancements** (Day 5 Afternoon) + - Add high contrast mode support + - Add visual focus indicators for mouse users + - Implement focus-within for nested focus + - Add aria-current for navigation + +**Deliverables:** +- Reduced motion support implemented +- Text scaling verified up to 200% +- Touch targets meet minimum sizes +- Enhanced accessibility features live + +--- + +## Technical Requirements + +### **1. Dependencies to Install** + +```bash +# Linting and Testing +npm install --save-dev eslint-plugin-jsx-a11y +npm install --save-dev jest-axe +npm install --save-dev @axe-core/react + +# Runtime Testing +npm install --save @axe-core/react + +# Focus Management +npm install react-focus-lock focus-trap-react + +# Reduced Motion Hook +npm install framer-motion # Already installed, use useReducedMotion +``` + +### **2. ESLint Configuration** + +Add to `.eslintrc.json`: + +```json +{ + "extends": [ + "plugin:jsx-a11y/recommended" + ], + "plugins": ["jsx-a11y"], + "rules": { + "jsx-a11y/anchor-is-valid": "error", + "jsx-a11y/aria-props": "error", + "jsx-a11y/aria-proptypes": "error", + "jsx-a11y/aria-unsupported-elements": "error", + "jsx-a11y/heading-has-content": "error", + "jsx-a11y/img-redundant-alt": "error", + "jsx-a11y/label-has-associated-control": "error", + "jsx-a11y/no-autofocus": "warn", + "jsx-a11y/no-static-element-interactions": "error" + } +} +``` + +### **3. Axe-Core Integration (Development)** + +Create `components/providers/AxeProvider.tsx`: + +```typescript +'use client'; + +import React, { useEffect } from 'react'; + +export function AxeProvider({ children }: { children: React.ReactNode }) { + useEffect(() => { + if (process.env.NODE_ENV === 'development') { + import('@axe-core/react').then((axe) => { + axe.default(React, require('react-dom'), 1000); + }); + } + }, []); + + return <>{children}; +} +``` + +### **4. Focus Visible Styles** + +Add to `globals.css`: + +```css +/* Focus indicators */ +*:focus { + outline: 2px solid #FF8B7D; /* Coral from design system */ + outline-offset: 2px; +} + +/* Focus visible (keyboard only) */ +*:focus:not(:focus-visible) { + outline: none; +} + +*:focus-visible { + outline: 2px solid #FF8B7D; + outline-offset: 2px; +} + +/* Skip link */ +.skip-link { + position: absolute; + top: -40px; + left: 0; + background: #000; + color: white; + padding: 8px; + text-decoration: none; + z-index: 100; +} + +.skip-link:focus { + top: 0; +} +``` + +### **5. Accessibility Utilities** + +Create `lib/accessibility.ts`: + +```typescript +/** + * Accessibility utility functions + */ + +// Announce to screen readers +export function announceToScreenReader(message: string, priority: 'polite' | 'assertive' = 'polite') { + const announcement = document.createElement('div'); + announcement.setAttribute('role', 'status'); + announcement.setAttribute('aria-live', priority); + announcement.setAttribute('aria-atomic', 'true'); + announcement.className = 'sr-only'; + announcement.textContent = message; + + document.body.appendChild(announcement); + + setTimeout(() => { + document.body.removeChild(announcement); + }, 1000); +} + +// Check if reduced motion is preferred +export function prefersReducedMotion(): boolean { + return window.matchMedia('(prefers-reduced-motion: reduce)').matches; +} + +// Get contrast ratio between two colors +export function getContrastRatio(color1: string, color2: string): number { + // Implementation using relative luminance formula + // WCAG requires 4.5:1 for normal text, 3:1 for large text +} + +// Trap focus within an element +export function trapFocus(element: HTMLElement) { + const focusableElements = element.querySelectorAll( + 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])' + ); + + const firstElement = focusableElements[0] as HTMLElement; + const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement; + + element.addEventListener('keydown', (e) => { + if (e.key === 'Tab') { + if (e.shiftKey && document.activeElement === firstElement) { + e.preventDefault(); + lastElement.focus(); + } else if (!e.shiftKey && document.activeElement === lastElement) { + e.preventDefault(); + firstElement.focus(); + } + } + }); +} +``` + +--- + +## Testing Strategy + +### **1. Automated Testing** + +#### **ESLint (Static Analysis)** +```bash +npm run lint # Check for accessibility violations +``` + +#### **jest-axe (Unit Tests)** +```typescript +import { render } from '@testing-library/react'; +import { axe, toHaveNoViolations } from 'jest-axe'; + +expect.extend(toHaveNoViolations); + +test('Dashboard should be accessible', async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); +}); +``` + +#### **Playwright (E2E Tests)** +```typescript +test('should pass accessibility audit', async ({ page }) => { + await page.goto('/dashboard'); + const accessibilityScanResults = await page.evaluate(async () => { + const axe = await import('axe-core'); + return await axe.run(); + }); + expect(accessibilityScanResults.violations).toEqual([]); +}); +``` + +#### **Lighthouse CI** +```bash +npm install --save-dev @lhci/cli +lhci autorun --collect.url=http://localhost:3000 --assert.preset=lighthouse:accessibility +``` + +### **2. Manual Testing Checklist** + +#### **Keyboard Navigation** +- [ ] All interactive elements are keyboard accessible +- [ ] Tab order is logical +- [ ] Focus indicators are visible +- [ ] Skip navigation link works +- [ ] No keyboard traps +- [ ] Escape key closes modals +- [ ] Enter/Space activate buttons + +#### **Screen Reader Testing** +- [ ] Page title is announced +- [ ] Headings are in logical order +- [ ] Form labels are announced +- [ ] Error messages are announced +- [ ] Status updates are announced +- [ ] Images have alt text +- [ ] Links have descriptive text + +#### **Visual Testing** +- [ ] Color contrast meets 4.5:1 (normal text) +- [ ] Color contrast meets 3:1 (large text, 18pt+) +- [ ] Content readable at 200% zoom +- [ ] No horizontal scrolling at 320px width +- [ ] Touch targets are 44x44px minimum + +#### **Assistive Technology** +- [ ] Works with NVDA (Windows) +- [ ] Works with JAWS (Windows) +- [ ] Works with VoiceOver (Mac/iOS) +- [ ] Works with TalkBack (Android) +- [ ] Works with Dragon NaturallySpeaking (voice control) +- [ ] Works with browser zoom + +### **3. Browser Testing Matrix** + +| Browser | Screen Reader | Platform | Status | +|---------|---------------|----------|--------| +| Chrome | NVDA | Windows | TODO | +| Firefox | NVDA | Windows | TODO | +| Edge | JAWS | Windows | TODO | +| Safari | VoiceOver | macOS | TODO | +| Safari | VoiceOver | iOS | TODO | +| Chrome | TalkBack | Android | TODO | + +--- + +## Success Metrics + +### **Quantitative Metrics** + +1. **Lighthouse Accessibility Score**: 100/100 ✅ +2. **Axe-core Violations**: 0 critical, 0 serious ✅ +3. **ESLint jsx-a11y Errors**: 0 ✅ +4. **Color Contrast**: 100% WCAG AA compliant ✅ +5. **Keyboard Navigation**: 100% of features accessible ✅ + +### **Qualitative Metrics** + +1. **Screen Reader Testing**: All critical user flows pass ✅ +2. **User Testing**: Test with 3-5 users with disabilities ✅ +3. **WCAG 2.1 AA Audit**: External audit (optional but recommended) ✅ + +### **Key User Flows to Test** + +1. ✅ **Sign Up / Log In** + - Keyboard accessible + - Error messages announced + - Form labels clear + +2. ✅ **Add Activity (Feeding/Sleep/Diaper)** + - Voice input accessible + - Form fully keyboard accessible + - Success message announced + +3. ✅ **View Dashboard** + - Stats cards readable + - Charts have text alternatives + - Navigation clear + +4. ✅ **AI Assistant Chat** + - Chat input keyboard accessible + - Responses announced to screen reader + - Conversation history navigable + +5. ✅ **Settings & Account** + - All settings keyboard accessible + - Toggle buttons have clear states + - Dialogs trap focus properly + +--- + +## Priority Order (Critical Path) + +### **Day 1 (Must Have)** +1. ESLint jsx-a11y setup +2. Visible focus indicators +3. Skip navigation link +4. Basic ARIA labels on buttons/links + +### **Days 2-3 (Critical)** +5. Keyboard navigation for all pages +6. Focus management for modals +7. Form labels and error messages +8. Heading hierarchy fixes + +### **Days 4-5 (High Priority)** +9. Alt text for all images +10. Color contrast fixes +11. Live regions for dynamic content +12. Automated tests (jest-axe) + +### **Week 2 (Testing & Polish)** +13. Screen reader testing +14. Manual keyboard testing +15. Reduced motion support +16. Documentation + +--- + +## Risk Mitigation + +### **Potential Risks** + +1. **Risk**: Breaking existing functionality + - **Mitigation**: Comprehensive testing after each change + +2. **Risk**: Time overrun + - **Mitigation**: Focus on critical items first (Days 1-3) + +3. **Risk**: Lack of screen reader expertise + - **Mitigation**: Use automated tools, watch video tutorials, hire consultant + +4. **Risk**: Design conflicts (e.g., focus indicators affect design) + - **Mitigation**: Work with design to create accessible alternatives + +--- + +## Resources + +### **Tools** +- [Axe DevTools Browser Extension](https://www.deque.com/axe/devtools/) +- [WAVE Browser Extension](https://wave.webaim.org/extension/) +- [Color Contrast Analyzer](https://www.tpgi.com/color-contrast-checker/) +- [Lighthouse](https://developers.google.com/web/tools/lighthouse) + +### **Documentation** +- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) +- [MDN Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility) +- [A11y Project Checklist](https://www.a11yproject.com/checklist/) +- [ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/) + +### **Screen Readers** +- [NVDA (Free, Windows)](https://www.nvaccess.org/) +- [JAWS (Trial, Windows)](https://www.freedomscientific.com/products/software/jaws/) +- VoiceOver (Built-in, macOS/iOS) +- TalkBack (Built-in, Android) + +--- + +## Next Steps + +1. ✅ **Review and approve this plan** +2. 🔄 **Start Phase 1, Day 1**: Install accessibility tools +3. 🔄 **Daily standups**: Review progress, adjust as needed +4. 🔄 **Test continuously**: Don't wait until the end + +--- + +**Document Owner**: Development Team +**Stakeholders**: Product, Design, QA, Legal +**Review Cadence**: Daily during implementation, weekly post-launch + +**Let's make the Maternal App accessible to ALL parents!** 🌟