Docs / Raw

Accessibility Audit

Sourced from docs/ACCESSIBILITY_AUDIT.md

Edit on GitHub

VoiceAssist Web App - Accessibility Audit & Improvements

Date: 2025-11-23 Target: WCAG 2.1 Level AA Compliance Status: In Progress

Executive Summary

This document tracks accessibility improvements for the VoiceAssist web application to achieve WCAG 2.1 Level AA compliance.

Current Status

✅ Already Implemented

  • Semantic HTML structure
  • Some ARIA labels on interactive elements
  • Keyboard navigation for chat input (Enter/Shift+Enter)
  • Focus management in dialogs
  • Skip-to-content patterns via React Router

⚠️ Needs Improvement

  1. Keyboard Navigation - Incomplete focus management
  2. ARIA Labels - Missing on some interactive elements
  3. Color Contrast - Not verified against WCAG standards
  4. Screen Reader Support - Limited live region announcements
  5. Focus Indicators - Could be more prominent
  6. Touch Targets - Some buttons may be too small (< 44x44px)

Detailed Audit

1. Keyboard Navigation

Issues:

  • ❌ No skip navigation link
  • ❌ Focus trap not implemented in all modals
  • ⚠️ Tab order may not be logical in complex layouts
  • ⚠️ Keyboard shortcuts need documentation

Improvements Needed:

// Add skip navigation <a href="#main-content" className="sr-only focus:not-sr-only"> Skip to main content </a> // Ensure all modals have focus trap // Use react-focus-lock or similar

2. ARIA Labels and Roles

Missing ARIA Labels:

  • ❌ Message list needs aria-live for new messages
  • ❌ Typing indicator needs aria-live="polite"
  • ❌ File upload progress needs aria-valuenow, aria-valuemin, aria-valuemax
  • ⚠️ Some icon buttons missing descriptive labels

Improvements:

// Message streaming <div aria-live="polite" aria-atomic="true"> {isTyping && <p>Assistant is typing...</p>} </div> // File upload progress <div role="progressbar" aria-valuenow={progress} aria-valuemin={0} aria-valuemax={100} aria-label="File upload progress" > {progress}% </div>

3. Color Contrast

Areas to Verify:

  • Primary buttons (bg-primary-500 with white text)
  • Secondary/ghost buttons
  • Placeholder text in inputs
  • Disabled state indicators
  • Link colors against backgrounds
  • Citation badges and tags
  • Clinical context form labels

Tool: Use Lighthouse or axe DevTools

Required Ratios (WCAG AA):

  • Normal text: 4.5:1
  • Large text (18pt+): 3:1
  • UI components: 3:1

4. Screen Reader Support

Issues:

  • ❌ No announcement when new message arrives
  • ❌ File upload success/error not announced
  • ❌ Citation sidebar opening not announced
  • ⚠️ Form validation errors need better association

Improvements:

// Add live region for announcements const [announcement, setAnnouncement] = useState(""); // Announce new messages useEffect(() => { if (newMessage && newMessage.role === "assistant") { setAnnouncement(`New message from assistant: ${newMessage.content.substring(0, 100)}`); } }, [newMessage]); <div role="status" aria-live="polite" aria-atomic="true" className="sr-only"> {announcement} </div>;

5. Forms and Inputs

Issues:

  • ⚠️ Some labels not properly associated with inputs
  • ❌ Error messages not linked with aria-describedby
  • ⚠️ Required fields not marked with aria-required

Improvements:

// Proper form field association <label htmlFor="patient-age" className="..."> Age <span aria-label="required">*</span> </label> <input id="patient-age" type="number" aria-required="true" aria-invalid={errors.age ? "true" : "false"} aria-describedby={errors.age ? "age-error" : undefined} /> {errors.age && ( <span id="age-error" role="alert" className="..."> {errors.age} </span> )}

6. Focus Management

Issues:

  • ⚠️ Focus outline could be more prominent
  • ❌ Focus not restored when closing modals
  • ❌ Focus not moved to first element in modals

Improvements:

/* Enhanced focus indicators */ *:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: 2px; } /* High contrast focus for critical elements */ button:focus-visible, a:focus-visible { outline: 3px solid var(--color-primary-500); outline-offset: 2px; }
// Focus management in modals useEffect(() => { if (isOpen) { const previouslyFocused = document.activeElement as HTMLElement; const firstFocusable = dialogRef.current?.querySelector( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', ) as HTMLElement; firstFocusable?.focus(); return () => { previouslyFocused?.focus(); }; } }, [isOpen]);

7. Semantic HTML

Current Status: ✅ Good

  • Using proper heading hierarchy (h1, h2, h3)
  • Lists use <ul>, <ol>, <li>
  • Buttons use <button> (not divs)
  • Links use <a> tags

Minor Improvements:

  • Add <main> landmark
  • Add <nav> for navigation areas
  • Add <aside> for sidebars
  • Add <article> for message bubbles

8. Images and Media

Issues:

  • ⚠️ Some SVG icons may lack proper titles
  • ❌ File preview images need alt text

Improvements:

// SVG with title <svg aria-labelledby="icon-title" role="img"> <title id="icon-title">Settings</title> <path d="..." /> </svg> // Image preview <img src={preview.url} alt={`Preview of uploaded file: ${file.name}`} loading="lazy" />

9. Mobile/Touch Accessibility

Issues:

  • ⚠️ Touch targets should be minimum 44x44px
  • ❌ No gesture alternatives for swipe actions

Verify Sizes:

  • Header buttons
  • Conversation list items
  • Message action buttons
  • Sidebar toggles

Implementation Plan

Phase 1: Critical (High Priority)

  1. Add skip navigation link
  2. Fix missing ARIA labels on icon buttons
  3. Implement live regions for dynamic content
  4. Add focus trap to all dialogs
  5. Verify and fix color contrast issues

Phase 2: Important (Medium Priority)

  1. Enhance focus indicators
  2. Add screen reader announcements
  3. Improve form error handling
  4. Add proper alt text to images
  5. Ensure touch targets are 44x44px minimum

Phase 3: Enhancement (Low Priority)

  1. Add keyboard shortcut help (already have dialog)
  2. Add skip links between major sections
  3. Implement reduced motion preferences
  4. Add high contrast mode support

Testing Strategy

Manual Testing:

  1. Keyboard Only - Navigate entire app without mouse
  2. Screen Reader - Test with NVDA/JAWS (Windows) or VoiceOver (Mac)
  3. Zoom - Test at 200% zoom (WCAG requirement)
  4. Color Blindness - Use simulators to test color dependency

Automated Testing:

  1. Lighthouse - Run accessibility audit
  2. axe DevTools - Browser extension scan
  3. WAVE - Web Accessibility Evaluation Tool
  4. pa11y - CI/CD integration

Tools:

# Install axe-core for testing npm install --save-dev @axe-core/react # Add to app entry point (dev only) if (process.env.NODE_ENV !== 'production') { import('@axe-core/react').then(axe => { axe.default(React, ReactDOM, 1000); }); }

Success Criteria

Must Have (WCAG AA):

  • All interactive elements keyboard accessible
  • All images have alt text
  • Color contrast ratios meet 4.5:1 (text) and 3:1 (UI)
  • Form inputs have labels
  • Error messages are associated with fields
  • Headings form logical hierarchy
  • Skip navigation available
  • Focus indicators visible
  • Live regions for dynamic content

Nice to Have (WCAG AAA / Best Practices):

  • Color contrast 7:1 for text
  • Comprehensive keyboard shortcuts
  • Reduced motion support
  • High contrast mode
  • Text spacing adjustable
  • Help documentation

Resources


Next Steps: Implement Phase 1 critical improvements and run automated testing.

Beginning of guide
End of guide