feat(a11y): improve accessibility - fix critical WCAG issues
Summary
First phase of comprehensive accessibility improvements based on thorough audit. This PR fixes all 6 critical accessibility issues that were blocking WCAG 2.1 Level A compliance.
Audit Results
Conducted comprehensive accessibility audit covering:
- ARIA labels and attributes
- Form accessibility
- Semantic HTML
- Heading hierarchy
- Keyboard navigation
- Images and media
- Links and navigation
- Color and contrast
- Dynamic content
- Component-specific issues
Total Issues Found: 28 issues
- π¨ Critical (6) - ALL FIXED IN THIS PR
- β οΈ Important (11) - Planned for follow-up
- π‘ Minor (11) - Planned for follow-up
Critical Issues Fixed (6/6) β
1. β Hamburger Menu - Non-Accessible Interactive Elements
Problem: Menu toggle used <div> with onClick instead of semantic <button>
Impact: Not keyboard accessible, screen readers didn't recognize as interactive
Fixed:
- Replaced div with proper button elements
- Added
aria-label="Open/Close navigation menu" - Added
aria-expanded={open}state - Added
sr-onlytext for screen reader users - Now fully keyboard accessible (Tab, Enter, Space)
- Fixed typo: "hambuger-nav" β "hamburger-nav"
File: src/components/Template/Hamburger.tsx
WCAG: 4.1.2 Name, Role, Value; 2.1.1 Keyboard
2. β Missing Skip Navigation Link
Problem: No skip-to-main-content link
Impact: Keyboard/screen reader users forced to tab through entire nav every page
Fixed:
- Added skip link before navigation in layout
- Visually hidden until keyboard focused
- Jumps directly to main content (#main)
- Styled with accessible focus indicator
File: app/layout.tsx
WCAG: 2.4.1 Bypass Blocks
3. β Main Landmark Missing
Problem: Main content used <div id="main"> instead of semantic <main>
Impact: Assistive technology couldn't easily find primary content
Fixed:
- Replaced div with semantic
<main>element - Added route announcer (aria-live region)
- Screen readers now announce page navigation
- Improved landmark navigation
File: app/components/PageWrapper.tsx
WCAG: 1.3.1 Info and Relationships; 4.1.3 Status Messages
4-5. β Focus Indicators Disabled
Problem: outline: none and outline: 0 removed focus indicators
Impact: Keyboard users couldn't see where they were navigating
Fixed:
- Added visible 2px blue focus outlines with offset
- Used
:focus-visibleto distinguish mouse vs keyboard - Applied to contact form elements and skill buttons
- Maintains clean mouse UX while restoring keyboard accessibility
Files:
src/static/css/pages/_contact.scsssrc/static/css/pages/_skills.scss
WCAG: 2.4.7 Focus Visible
6. β Empty Decorative Elements
Problem: Empty .link-to divs confused screen readers
Impact: Screen readers announced meaningless empty elements
Fixed:
- Added
aria-hidden="true"to 5 decorative divs - Hides from assistive technology
- Maintains visual anchor functionality
File: app/resume/page.tsx
WCAG: 1.3.1 Info and Relationships
CSS Utilities Added
.sr-only Class
Screen reader only text (visually hidden but accessible to AT):
.sr-only {
position: absolute;
width: 1px;
height: 1px;
// ... clips content outside visible area
}
.skip-link Class
Skip navigation styling:
.skip-link {
position: absolute;
top: -40px; // Hidden off-screen
// ... becomes visible on focus
}
File: src/static/css/base/_page.scss
Testing
Build & Quality
- β
Production build successful (
npm run build) - β
Linting passed (
npm run lint) - β
Formatting passed (
npm run format) - β TypeScript compilation passed
- β All tests passed
Accessibility Testing Checklist
Manual testing recommended:
- [ ] Keyboard navigation (Tab through entire site)
- [ ] Skip link appears and works on Tab focus
- [ ] Hamburger menu opens/closes with keyboard (Enter/Space)
- [ ] Focus indicators visible on all interactive elements
- [ ] Screen reader announces page changes (VoiceOver/NVDA)
- [ ] Main landmark navigable in screen reader
Impact & Benefits
Immediate Benefits
β
Keyboard Navigation: All interactive elements now keyboard accessible
β
Screen Reader Support: Proper ARIA labels and semantic HTML
β
Focus Management: Visible focus indicators for keyboard users
β
Skip Navigation: Efficient navigation for AT users
β
Semantic HTML: Proper landmarks for better AT navigation
Compliance Progress
Before: β Failed WCAG 2.1 Level A (critical keyboard/semantic issues)
After: β
Moving towards WCAG 2.1 Level A compliance
Code Quality
- Added reusable accessibility utility classes
- Improved semantic HTML structure
- Better separation of concerns
- Modern accessibility best practices
Remaining Work (Not in This PR)
Important Issues (11) - Recommended for Follow-up PR
- Missing ARIA labels on navigation regions
- Navigation semantic HTML improvements
- EmailLink component accessibility (invalid href, keyboard events)
- Project links need better labeling
- Table accessibility (captions, scope attributes)
- SkillBar ARIA attributes for progress indication
- Resume section navigation semantics
- SideBar landmark roles (aside, footer)
- And more...
Minor Issues (11) - Nice to Have
- External links not marked
- Heading hierarchy improvements
- Missing datetime attributes on dates
- CategoryButton active state announcements
- Suspense fallback improvements
- ContactIcons external link indication
- And more...
Recommendation: Address important issues in a follow-up PR to avoid this PR becoming too large.
Breaking Changes
None - All changes are backward compatible and enhance existing functionality.
Related Documentation
Files Changed (7 files, +103/-19 lines)
Components
src/components/Template/Hamburger.tsx- Made hamburger menu accessible
Pages
app/layout.tsx- Added skip navigation linkapp/components/PageWrapper.tsx- Changed to main landmark, added route announcerapp/resume/page.tsx- Added aria-hidden to decorative elements
Styles
src/static/css/base/_page.scss- Added accessibility utility classessrc/static/css/pages/_contact.scss- Fixed focus indicatorssrc/static/css/pages/_skills.scss- Fixed focus indicators
This PR represents Phase 1 of accessibility improvements, focusing on the most critical issues that completely blocked keyboard and screen reader access. Ready for review and testing!
π€ Generated with Claude Code
Deploying mldangelo with Β
Β Cloudflare Pages
| Latest commit: |
60ba844
|
| Status: | Β β Β Deploy successful! |
| Preview URL: | https://e4db6f26.mldangelo.pages.dev |
| Branch Preview URL: | https://feat-accessibility-improveme.mldangelo.pages.dev |