|
| 1 | +# Accessibility Audit & Implementation Plan - Issue #993 |
| 2 | + |
| 3 | +## Executive Summary |
| 4 | +This document outlines the findings from a comprehensive accessibility audit of YieldVault-RWA's UI/UX across core flows, with focus on WCAG 2.1 AA compliance for contrast and typography. |
| 5 | + |
| 6 | +**Current Status**: Strong foundation with comprehensive ARIA implementation and axe-core testing. Identified specific gaps in contrast, typography consistency, and edge cases. |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## 1. Audit Findings |
| 11 | + |
| 12 | +### ✅ Existing Strengths |
| 13 | +- **ARIA Implementation**: Comprehensive use of roles, labels, and attributes across components |
| 14 | +- **Color Variables**: Well-defined dark/light theme tokens with documented contrast ratios |
| 15 | +- **Keyboard Navigation**: Focus management, focus traps, skip links, keyboard shortcuts |
| 16 | +- **Semantic HTML**: Proper heading hierarchy, table structure, form associations |
| 17 | +- **Testing Foundation**: axe-core integration with 15+ test cases covering WCAG 2.1 AA |
| 18 | + |
| 19 | +### ⚠️ Identified Issues |
| 20 | + |
| 21 | +#### A. Contrast & Color Issues |
| 22 | + |
| 23 | +1. **HealthStatusIndicator**: Tooltip text lacks sufficient contrast |
| 24 | + - Issue: `.6` opacity on `--text-secondary` over surface backgrounds |
| 25 | + - Severity: Medium |
| 26 | + - Fix: Increase base contrast or reduce opacity dependency |
| 27 | + |
| 28 | +2. **Tabs Component**: Inactive tab contrast may fail in certain scenarios |
| 29 | + - Current: `var(--text-secondary)` on `var(--bg-muted)` with transparency |
| 30 | + - Issue: Semi-transparent backgrounds reduce effective contrast |
| 31 | + - Severity: Medium |
| 32 | + - Fix: Use solid background or adjust text color |
| 33 | + |
| 34 | +3. **Badge Component (Info & Warning)**: |
| 35 | + - Info badge: `#3b82f6` on `rgba(59, 130, 246, 0.1)` - needs verification |
| 36 | + - Warning badge: `#f59e0b` on `rgba(245, 158, 11, 0.1)` - needs verification |
| 37 | + - Severity: Medium |
| 38 | + - Fix: Ensure 3:1 minimum for large text, 4.5:1 for normal |
| 39 | + |
| 40 | +4. **Disabled Button States**: |
| 41 | + - Current: Uses opacity 0.5 on all disabled buttons |
| 42 | + - Issue: Poor contrast for users with cognitive disabilities |
| 43 | + - Severity: High |
| 44 | + - Fix: Add explicit contrast-compliant styling for disabled states |
| 45 | + |
| 46 | +5. **Error States**: |
| 47 | + - Text: `#ff6b6b` vs Background: `rgba(255, 50, 50, 0.1)` (light theme: `#dc2626` vs `rgba(239, 68, 68, 0.1)`) |
| 48 | + - Issue: Light backgrounds + bright text may fail contrast |
| 49 | + - Severity: Medium |
| 50 | + - Fix: Verify and adjust error color palette |
| 51 | + |
| 52 | +#### B. Typography Issues |
| 53 | + |
| 54 | +1. **Inconsistent Font Sizes Across Themes**: |
| 55 | + - Dark theme body: `var(--text-base)` (16px) |
| 56 | + - Light theme body: Not explicitly set (defaults to base) |
| 57 | + - Issue: Line-height varies by context |
| 58 | + - Severity: Low |
| 59 | + - Fix: Ensure consistent sizing in light theme |
| 60 | + |
| 61 | +2. **Small Text Contrast**: |
| 62 | + - `--text-xs` (12px) with `--text-tertiary` + small fonts used in several places |
| 63 | + - Issue: Combined small size + tertiary color reduces readability |
| 64 | + - Severity: Medium |
| 65 | + - Fix: Reduce use of `--text-xs` + `--text-tertiary` combination |
| 66 | + |
| 67 | +3. **Missing Text Size Scaling**: |
| 68 | + - Some components use hardcoded pixel sizes |
| 69 | + - Issue: Doesn't respect user's `prefers-reduced-motion` and text scaling preferences |
| 70 | + - Severity: Low |
| 71 | + - Fix: Use CSS custom properties and `rem`-based units |
| 72 | + |
| 73 | +4. **Breadcrumb Typography**: |
| 74 | + - Font size: `0.9rem` (hardcoded) |
| 75 | + - Color: `var(--text-secondary)` |
| 76 | + - Issue: Small size + secondary color = 14.4px at reduced contrast |
| 77 | + - Severity: Low |
| 78 | + - Fix: Use `var(--text-sm)` and verify contrast |
| 79 | + |
| 80 | +5. **Modal/Dialog Title Font Size**: |
| 81 | + - No consistent sizing rule across modals |
| 82 | + - Issue: Some titles may be too small (varies by implementation) |
| 83 | + - Severity: Low |
| 84 | + - Fix: Define `--modal-title-size` and apply consistently |
| 85 | + |
| 86 | +#### C. Focus & Keyboard Navigation |
| 87 | + |
| 88 | +1. **Focus Styles on All Components**: |
| 89 | + - ✅ Most components have visible focus styles (2px cyan outline) |
| 90 | + - ⚠️ Some custom components (like HealthStatusIndicator button) may lack clear focus |
| 91 | + - Severity: Low |
| 92 | + - Fix: Add focus-visible to all interactive elements |
| 93 | + |
| 94 | +2. **Modal Backdrop Interaction**: |
| 95 | + - ✅ Modal includes `closeOnEscape` and `closeOnBackdropClick` |
| 96 | + - ✅ Focus trap implemented |
| 97 | + - Status: Compliant |
| 98 | + |
| 99 | +#### D. Missing Documentation |
| 100 | + |
| 101 | +1. **Accessibility Guidelines Document**: Not present |
| 102 | + - Should document color contrast ranges, font sizing strategy, etc. |
| 103 | + - Severity: Low |
| 104 | + |
| 105 | +2. **Component Accessibility Props**: Not documented |
| 106 | + - Should document available ARIA props for each component |
| 107 | + - Severity: Low |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +## 2. Implementation Tasks |
| 112 | + |
| 113 | +### Phase 1: Critical Fixes (Contrast & Color) |
| 114 | + |
| 115 | +#### Task 1.1: Fix Disabled Button Contrast |
| 116 | +- **Files**: `frontend/src/index.css` (add `:disabled` styles) |
| 117 | +- **Action**: Create explicit high-contrast disabled state |
| 118 | +- **Before**: `opacity: 0.5` (variable contrast) |
| 119 | +- **After**: Solid color with 4.5:1+ minimum contrast |
| 120 | +- **Test**: Add test case for disabled button contrast |
| 121 | + |
| 122 | +#### Task 1.2: Fix Badge Component Contrast |
| 123 | +- **Files**: `frontend/src/components/Badge.tsx` |
| 124 | +- **Action**: Verify all badge color combinations meet 3:1 (large) or 4.5:1 (normal) contrast |
| 125 | +- **Severity**: Calculate contrast ratios for each variant + color combo |
| 126 | +- **Test**: Add parametrized contrast tests for all badge combinations |
| 127 | + |
| 128 | +#### Task 1.3: Fix HealthStatusIndicator Tooltip Contrast |
| 129 | +- **Files**: `frontend/src/components/HealthStatusIndicator.tsx` |
| 130 | +- **Action**: |
| 131 | + - Remove opacity dependency on secondary text in tooltip |
| 132 | + - Use solid color or primary text color |
| 133 | + - Ensure status indicator dot is distinguishable from background |
| 134 | +- **Test**: Add axe-core test for this component |
| 135 | + |
| 136 | +#### Task 1.4: Fix Tabs Inactive State Contrast |
| 137 | +- **Files**: `frontend/src/components/Tabs.css`, `frontend/src/components/Tabs.tsx` |
| 138 | +- **Action**: |
| 139 | + - Replace transparent tab background with solid color |
| 140 | + - Ensure inactive tab text meets 4.5:1 contrast |
| 141 | + - Consider using lighter opacity on solid background |
| 142 | +- **Test**: Add contrast test for inactive tabs |
| 143 | + |
| 144 | +#### Task 1.5: Fix Error State Colors |
| 145 | +- **Files**: `frontend/src/index.css` |
| 146 | +- **Action**: |
| 147 | + - Calculate contrast for `--text-error` on `--bg-error` |
| 148 | + - Adjust colors if needed to meet 4.5:1 |
| 149 | + - Update light theme error colors |
| 150 | +- **Test**: Add error state contrast tests |
| 151 | + |
| 152 | +### Phase 2: Typography & Readability |
| 153 | + |
| 154 | +#### Task 2.1: Standardize Small Text Usage |
| 155 | +- **Files**: `frontend/src/index.css`, component files using `--text-xs` |
| 156 | +- **Action**: |
| 157 | + - Replace unsafe `--text-xs` + `--text-tertiary` combinations |
| 158 | + - Use `--text-sm` + `--text-secondary` for minimum readability |
| 159 | + - Limit `--text-xs` to labels and helper text only |
| 160 | +- **Test**: Add readability tests |
| 161 | + |
| 162 | +#### Task 2.2: Fix Breadcrumb Typography |
| 163 | +- **Files**: `frontend/src/components/PageHeader.tsx` |
| 164 | +- **Action**: |
| 165 | + - Change hardcoded `fontSize: "0.9rem"` to use CSS variable |
| 166 | + - Use `var(--text-sm)` instead |
| 167 | + - Verify contrast against background |
| 168 | +- **Test**: Add breadcrumb accessibility test |
| 169 | + |
| 170 | +#### Task 2.3: Ensure Consistent Modal Typography |
| 171 | +- **Files**: `frontend/src/index.css` |
| 172 | +- **Action**: |
| 173 | + - Add modal-specific typography rules |
| 174 | + - Define `--modal-title-size: var(--text-2xl)` |
| 175 | + - Define `--modal-body-size: var(--text-base)` |
| 176 | +- **Files affected**: All modal components |
| 177 | +- **Test**: Add modal typography consistency test |
| 178 | + |
| 179 | +#### Task 2.4: Add Text Scaling Support |
| 180 | +- **Files**: `frontend/src/index.css` |
| 181 | +- **Action**: |
| 182 | + - Update body font-size to use `clamp()` for responsive scaling |
| 183 | + - Ensure heading sizes scale appropriately |
| 184 | + - Test with browser text scaling (125%, 150%) |
| 185 | +- **Test**: Manual browser scaling test (document with screenshots) |
| 186 | + |
| 187 | +### Phase 3: Focus & Keyboard Navigation |
| 188 | + |
| 189 | +#### Task 3.1: Audit Focus Styles |
| 190 | +- **Files**: All interactive components |
| 191 | +- **Action**: |
| 192 | + - Verify all interactive elements have `:focus-visible` styles |
| 193 | + - Ensure 2px cyan outline or equivalent |
| 194 | + - Check custom button/link components |
| 195 | +- **Specific components**: HealthStatusIndicator, Badge (if interactive), custom buttons |
| 196 | +- **Test**: Focus chain test with Tab key |
| 197 | + |
| 198 | +#### Task 3.2: Test Keyboard Navigation in Core Flows |
| 199 | +- **Test scenarios**: |
| 200 | + 1. Home flow: Tab through vault selection |
| 201 | + 2. Portfolio flow: Tab through buttons, charts, data table |
| 202 | + 3. Transaction history: Tab through table, pagination, filters |
| 203 | + 4. Settings: Tab through language/theme toggles |
| 204 | +- **Test coverage**: Manual testing guide + automation where possible |
| 205 | +- **Test**: Document keyboard navigation paths |
| 206 | + |
| 207 | +### Phase 4: Testing & Documentation |
| 208 | + |
| 209 | +#### Task 4.1: Expand axe-core Tests |
| 210 | +- **Files**: `frontend/src/tests/accessibility.test.tsx` |
| 211 | +- **Action**: |
| 212 | + - Add tests for all badge color combinations |
| 213 | + - Add HealthStatusIndicator component test |
| 214 | + - Add Tabs component test |
| 215 | + - Add disabled button state test |
| 216 | + - Add error state test |
| 217 | +- **Coverage**: Aim for 25+ test cases |
| 218 | + |
| 219 | +#### Task 4.2: Add Manual Test Guide |
| 220 | +- **Files**: Create `ACCESSIBILITY_TEST_GUIDE.md` |
| 221 | +- **Content**: |
| 222 | + - Keyboard navigation paths for each page |
| 223 | + - Screen reader testing guide (NVDA, JAWS, Safari VoiceOver) |
| 224 | + - Color contrast verification checklist |
| 225 | + - Browser text scaling test (125%, 150%) |
| 226 | + - High contrast mode testing |
| 227 | + - Zoom level testing (200%) |
| 228 | +- **Test**: Manual verification documented |
| 229 | + |
| 230 | +#### Task 4.3: Create Accessibility Design System Documentation |
| 231 | +- **Files**: Create `ACCESSIBILITY_GUIDELINES.md` |
| 232 | +- **Content**: |
| 233 | + - Color usage guidelines (contrast thresholds) |
| 234 | + - Typography scale and sizing rules |
| 235 | + - Touch target sizing (minimum 44x44px) |
| 236 | + - Focus style conventions |
| 237 | + - ARIA usage patterns |
| 238 | + - Common pitfalls and solutions |
| 239 | + |
| 240 | +#### Task 4.4: Update Main README |
| 241 | +- **Files**: `frontend/README.md` (if exists) or main `README.md` |
| 242 | +- **Action**: Add accessibility section with: |
| 243 | + - Current WCAG 2.1 AA compliance status |
| 244 | + - How to run accessibility tests |
| 245 | + - Links to accessibility guidelines |
| 246 | + - Contact info for accessibility issues |
| 247 | + |
| 248 | +### Phase 5: CI/CD Integration |
| 249 | + |
| 250 | +#### Task 5.1: Add Accessibility Check to CI Pipeline |
| 251 | +- **Files**: Update GitHub Actions workflow (if desired) |
| 252 | +- **Action**: |
| 253 | + - Add `npm run test` to ensure accessibility tests pass |
| 254 | + - Optional: Add pre-commit hook for accessibility lint |
| 255 | +- **Test**: Verify CI integration works |
| 256 | + |
| 257 | +--- |
| 258 | + |
| 259 | +## 3. Verification Checklist |
| 260 | + |
| 261 | +### Contrast & Color Verification |
| 262 | +- [ ] All text meets 4.5:1 contrast (normal text) |
| 263 | +- [ ] Large text (18pt+) meets 3:1 contrast |
| 264 | +- [ ] Disabled buttons have explicit styling with sufficient contrast |
| 265 | +- [ ] All badge variants pass contrast tests |
| 266 | +- [ ] Error states meet contrast requirements |
| 267 | +- [ ] Focus indicators meet contrast requirements |
| 268 | + |
| 269 | +### Typography Verification |
| 270 | +- [ ] Font sizes scale appropriately from 12px to 60px |
| 271 | +- [ ] Line heights are between 1.2 and 2 |
| 272 | +- [ ] Small text (`--text-xs`) is used only for secondary labels |
| 273 | +- [ ] Headings use consistent font-family (display) |
| 274 | +- [ ] Body text uses sans-serif system font stack |
| 275 | + |
| 276 | +### Keyboard & Focus Verification |
| 277 | +- [ ] Tab key navigates through all interactive elements in logical order |
| 278 | +- [ ] All interactive elements have visible focus styles |
| 279 | +- [ ] Focus trap works in modals |
| 280 | +- [ ] Escape key closes modals and dialogs |
| 281 | +- [ ] No keyboard traps in core flows |
| 282 | + |
| 283 | +### Accessibility Testing Verification |
| 284 | +- [ ] axe-core tests pass with zero violations |
| 285 | +- [ ] Skip-link test passes |
| 286 | +- [ ] All ARIA attributes are valid and present |
| 287 | +- [ ] Screen reader testing completed (at least Safari VoiceOver) |
| 288 | +- [ ] Keyboard-only navigation verified for all pages |
| 289 | + |
| 290 | +--- |
| 291 | + |
| 292 | +## 4. Core Flows to Test |
| 293 | + |
| 294 | +1. **Home/Dashboard Flow** |
| 295 | + - Landing page → Vault selection → Deposit/Withdraw tabs |
| 296 | + - Test contrast, typography, tab navigation |
| 297 | + |
| 298 | +2. **Portfolio Flow** |
| 299 | + - Portfolio dashboard → Charts → Holdings table |
| 300 | + - Test chart accessibility, table navigation, text scaling |
| 301 | + |
| 302 | +3. **Transaction History Flow** |
| 303 | + - Transaction list → Sorting → Pagination → Transaction details |
| 304 | + - Test table contrast, button states, pagination labels |
| 305 | + |
| 306 | +4. **Settings Flow** |
| 307 | + - Settings page → Language toggle → Theme toggle |
| 308 | + - Test toggle accessibility, label visibility |
| 309 | + |
| 310 | +5. **Error/Warning Flows** |
| 311 | + - Session expiration → Error states → Recovery flows |
| 312 | + - Test error message contrast, alert roles, recovery paths |
| 313 | + |
| 314 | +--- |
| 315 | + |
| 316 | +## 5. Testing Tools & Methods |
| 317 | + |
| 318 | +### Automated Testing |
| 319 | +- **axe-core**: WCAG 2.1 AA automated audit |
| 320 | +- **jest/vitest**: Component-level tests |
| 321 | +- **Playwright**: End-to-end keyboard navigation tests |
| 322 | + |
| 323 | +### Manual Testing |
| 324 | +- **Browser DevTools**: Inspect contrast using built-in tools |
| 325 | +- **WCAG Color Contrast Checker**: Verify specific color combinations |
| 326 | +- **Screen Readers**: |
| 327 | + - macOS: Safari VoiceOver (built-in) |
| 328 | + - Linux: NVDA |
| 329 | + - Windows: JAWS |
| 330 | +- **Zoom/Text Scaling**: Test at 125%, 150%, 200% |
| 331 | +- **High Contrast Mode**: Windows High Contrast testing |
| 332 | +- **Mobile**: Test touch targets on iOS/Android |
| 333 | + |
| 334 | +### Tools & Links |
| 335 | +- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) |
| 336 | +- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) |
| 337 | +- [axe DevTools Browser Extension](https://www.deque.com/axe/devtools/) |
| 338 | +- [Color.review](https://color.review/) - contrast checking |
| 339 | + |
| 340 | +--- |
| 341 | + |
| 342 | +## 6. Acceptance Criteria (Issue #993) |
| 343 | + |
| 344 | +- [x] Implementation completed (in progress) |
| 345 | +- [ ] Tests added or updated (unit/integration/e2e) |
| 346 | +- [ ] Relevant documentation updated |
| 347 | +- [ ] CI checks pass with no regressions |
| 348 | +- [ ] Manual accessibility testing completed and documented |
| 349 | +- [ ] All identified contrast issues resolved |
| 350 | +- [ ] All typography consistency issues resolved |
| 351 | +- [ ] Keyboard navigation verified on all core flows |
| 352 | +- [ ] Zero axe-core violations on all tested components |
| 353 | + |
| 354 | +--- |
| 355 | + |
| 356 | +## 7. Timeline & Priority |
| 357 | + |
| 358 | +### High Priority (Week 1) |
| 359 | +- Task 1.1: Fix disabled button contrast |
| 360 | +- Task 1.2: Fix badge contrast |
| 361 | +- Task 1.3: Fix HealthStatusIndicator tooltip |
| 362 | +- Task 4.1: Expand axe-core tests |
| 363 | + |
| 364 | +### Medium Priority (Week 2) |
| 365 | +- Task 1.4: Fix tabs contrast |
| 366 | +- Task 1.5: Fix error state colors |
| 367 | +- Task 2.1: Standardize small text |
| 368 | +- Task 4.2: Add manual test guide |
| 369 | + |
| 370 | +### Low Priority (Week 3) |
| 371 | +- Task 2.2: Fix breadcrumb typography |
| 372 | +- Task 2.3: Ensure modal typography |
| 373 | +- Task 2.4: Add text scaling support |
| 374 | +- Task 3.1: Audit focus styles |
| 375 | +- Task 4.3: Create design guidelines |
| 376 | +- Task 5.1: CI/CD integration |
| 377 | + |
| 378 | +--- |
| 379 | + |
| 380 | +## 8. Related Issues & References |
| 381 | + |
| 382 | +- **Issue #239**: Referenced in existing accessibility tests |
| 383 | +- **WCAG 2.1 AA**: Target compliance standard |
| 384 | +- **Existing test file**: `frontend/src/tests/accessibility.test.tsx` (450+ lines) |
| 385 | +- **Color variables**: `frontend/src/index.css` (well-documented) |
| 386 | + |
| 387 | +--- |
| 388 | + |
| 389 | +## Notes |
| 390 | + |
| 391 | +- Current implementation has a strong foundation; issues are primarily refinement-level |
| 392 | +- Team should prioritize high-contrast scenarios for users with color vision deficiency |
| 393 | +- Recommend regular accessibility audits as part of sprint planning |
| 394 | +- Consider appointing accessibility champion on team for ongoing compliance |
0 commit comments