Root directory had accumulated audit/exploration markdown files cluttering the project root. Moved all audit-related files to docs/audits/ with a README.md index, and updated cross-references in K6_LOAD_TESTING_GUIDE.md and README_FRONTEND_DOCS.md. Co-Authored-By: Paperclip <noreply@paperclip.ing>
8.6 KiB
GoodGo Platform Accessibility Audit - Quick Reference
Date: April 10, 2026 | Status: 70-75% WCAG 2.1 AA Compliant
📊 Key Metrics
| Metric | Count | Status |
|---|---|---|
| Total Files Analyzed | 90+ | ✅ |
| ARIA Attributes Found | 75 | ✅ |
| Files Using ARIA | 14 | ✅ |
| Critical Issues | 2 | 🔴 |
| Major Issues | 3 | 🟡 |
| Minor Issues | 2 | 🟢 |
🔴 CRITICAL ISSUES (Must Fix)
1. Dialog Component Missing Accessibility
File: apps/web/components/ui/dialog.tsx
Issues:
- Missing
role="dialog" - Missing
aria-modal="true" - No focus trap
- No escape key handling
- Background not hidden from screen readers
Time to Fix: 2-3 hours | Priority: 1
Quick Fix Checklist:
- Add role="dialog" to dialog container
- Add aria-modal="true"
- Implement escape key listener
- Add aria-hidden="true" to backdrop
- Test with NVDA screen reader
2. Image Gallery Thumbnail Buttons Missing Labels
File: apps/web/components/listings/image-gallery.tsx:69-84
Issue: Thumbnail buttons lack aria-labels
Time to Fix: 15-30 minutes | Priority: 2
Quick Fix:
// Add this to each thumbnail button:
aria-label={`Select image ${index + 1}${img.caption ? ': ' + img.caption : ''}`}
aria-pressed={index === selectedIndex}
🟡 MAJOR ISSUES (Should Fix)
1. Admin Layout Header Missing Banner Role
File: apps/web/app/[locale]/(admin)/layout.tsx:134
Quick Fix:
// Change from:
<header className="sticky...">
// To:
<header role="banner" className="sticky...">
Time to Fix: 2 minutes | Priority: 3
2. Color Contrast Not Verified
Issue: CSS variables defined but contrast ratios not tested Impact: Potential WCAG 1.4.3 violation Time to Fix: 4-6 hours testing
Testing Checklist:
- Extract CSS variable values from globals.css
- Test with WebAIM Contrast Checker
- Verify 4.5:1 for normal text (WCAG AA)
- Verify 7:1 for AAA compliance
- Test in both light and dark modes
3. Landing Page Search Input Missing Visible Label
File: apps/web/app/[locale]/(public)/page.tsx:87-92
Quick Fix:
<div className="flex flex-col gap-1">
<label htmlFor="search-input" className="sr-only">
{t('landing.searchPlaceholder')}
</label>
<Input
id="search-input"
placeholder={t('landing.searchPlaceholder')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
Time to Fix: 30 minutes | Priority: 4
🟢 MINOR ISSUES (Nice to Have)
1. Redundant aria-labels on Visible Text
File: apps/web/app/[locale]/(dashboard)/layout.tsx:125
Issue: Links have aria-label when text is already visible
Recommendation: Remove redundant aria-labels - visible text is better for accessibility
✅ WHAT'S WORKING WELL
Authentication Forms
- ✅ All inputs have visible labels with
<Label htmlFor="id"> - ✅ Error messages linked via
aria-describedby - ✅ Invalid state marked with
aria-invalid - ✅ Password toggle has proper
aria-label - Example:
apps/web/app/[locale]/(auth)/login/page.tsx
Skip-to-Content Link
- ✅ Properly implemented with focus visibility
- ✅ Hidden by default, visible on focus
- ✅ Links to
id="main-content" - Example:
apps/web/app/[locale]/layout.tsx:105-110
Navigation
- ✅ All navs have
aria-label - ✅ Mobile menu toggles have dynamic labels
- ✅ Icons properly hidden with
aria-hidden="true" - Examples: All layout files
Search & Filters
- ✅ Filter section has
role="search" - ✅ All selects have
aria-label - ✅ Range inputs properly labeled
- Example:
apps/web/components/search/filter-bar.tsx
Image Gallery
- ✅ Previous/Next buttons have aria-labels
- ✅ Good semantic structure
- Example:
apps/web/components/listings/image-gallery.tsx:47, 54
📋 TESTING CHECKLIST
Before Deployment
- Fix dialog component accessibility
- Add thumbnail button labels
- Add banner role to admin header
- Run Lighthouse accessibility audit (target: 90+)
- Test with NVDA screen reader
- Test keyboard navigation (Tab, Shift+Tab, Enter, Escape)
- Verify color contrast ratios
- Test theme switching (light/dark mode)
Screen Reader Testing (NVDA)
- Login form: Can fill fields, hear error messages
- Navigation: Can navigate menus, understand current page
- Search: Can find and submit search form
- Dialogs: Can open, interact, close with Escape key
- Image gallery: Can select images, hear which is selected
- Mobile menu: Can open/close, toggle working properly
Keyboard Navigation
- Tab: Moves through all interactive elements in logical order
- Shift+Tab: Moves backward through elements
- Enter: Activates buttons/links/form submission
- Space: Activates buttons, toggles checkboxes
- Escape: Closes modals/menus
- Arrow keys: Works in dropdowns/carousels
🎯 Priority Roadmap
Week 1 (40 hours)
-
Fix Dialog Component (2-3 hrs)
- Add role, aria-modal, focus trap, escape handling
- Test with screen reader
-
Add Thumbnail Labels (0.5 hrs)
- Add aria-label to thumbnail buttons
- Test
-
Fix Admin Header (0.1 hrs)
- Add role="banner"
-
Verify Contrast (6-8 hrs)
- Extract CSS variables
- Test all combinations
- Document findings
- Adjust if needed
-
Add Landing Page Label (0.5 hrs)
- Add visible label to search input
-
Browser Testing (8 hrs)
- NVDA testing
- Chrome/Firefox/Safari testing
- Mobile testing
Week 2 (20 hours)
- Remove Redundant Labels (0.5 hrs)
- Additional Skip Links (2-3 hrs)
- Comprehensive Testing (8 hrs)
- Fix Any Found Issues (6 hrs)
📁 File Reference
Critical Files to Review/Fix
apps/web/components/ui/dialog.tsx- 🔴 REWRITE NEEDEDapps/web/components/listings/image-gallery.tsx- 🔴 MINOR FIX NEEDEDapps/web/app/[locale]/(admin)/layout.tsx- 🟡 ADD ROLEapps/web/app/globals.css- 🟡 VERIFY COLORS (not audited)
Files with Good Accessibility
apps/web/app/[locale]/(public)/layout.tsx- ✅ EXCELLENTapps/web/app/[locale]/(auth)/login/page.tsx- ✅ EXCELLENTapps/web/app/[locale]/(auth)/register/page.tsx- ✅ EXCELLENTapps/web/components/ui/button.tsx- ✅ GOODapps/web/components/ui/input.tsx- ✅ GOODapps/web/components/ui/label.tsx- ✅ GOODapps/web/components/ui/select.tsx- ✅ GOODapps/web/components/search/filter-bar.tsx- ✅ GOOD
🔍 Code Examples
Good ARIA Usage Example
// Good: Dynamic aria-label that updates based on state
<button
aria-label={mobileMenuOpen ? t('nav.closeMenu') : t('nav.openMenu')}
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X /> : <Menu />}
</button>
Form Accessibility Example
// Good: Proper label association + error handling
<div className="space-y-2">
<Label htmlFor="phone">{t('phone')}</Label>
<Input
id="phone"
type="tel"
aria-describedby={errors.phone ? 'phone-error' : undefined}
aria-invalid={!!errors.phone}
{...register('phone')}
/>
{errors.phone && (
<p id="phone-error" role="alert">{errors.phone.message}</p>
)}
</div>
Search Form Example
// Good: Proper semantic role with labeled controls
<form role="search" aria-label={t('filters')}>
<Select aria-label={t('allTransactions')}>
{/* options */}
</Select>
</form>
📞 Resources
Documentation
- Full audit report:
ACCESSIBILITY_AUDIT_2026-04-10.md - Detailed findings on 15 sections
- File-by-file analysis
- WCAG 2.1 compliance assessment
Testing Tools
- Axe DevTools: Chrome/Firefox extension for quick checks
- Lighthouse: Built into Chrome DevTools
- WebAIM Contrast Checker: https://webaim.org/resources/contrastchecker/
- NVDA: Free screen reader - https://www.nvaccess.org/
Learning Resources
📝 Notes
Audit Scope: apps/web (Next.js 14 frontend) Files Analyzed: 90+ TSX/JSX files Time to Achieve AA Compliance: 4-6 days full-time Ongoing Maintenance: Add to CI/CD, developer training recommended
Next Steps:
- Review full audit report (1552 lines)
- Create Jira tickets for each issue
- Assign tasks to development team
- Schedule accessibility testing
- Plan developer training session