Building Accessible Web Applications: A Developer's Guide
Accessibility isn't just about compliance—it's about building products that work for everyone. With 15% of the world's population experiencing some form of disability, accessible design expands your market and improves usability for all users.
Why Accessibility Matters
Business Case
Expanded Market: 1 billion people worldwide have disabilities
Legal Requirements: ADA compliance is mandatory for many businesses
SEO Benefits: Accessible sites rank better in search engines
Better UX: Accessible design improves experience for all users
Brand Reputation: Shows commitment to inclusivity
Ethical Imperative
Everyone deserves equal access to information and services online.
WCAG 2.1 Principles (POUR)
Perceivable
Information must be presentable to users in ways they can perceive.
Examples:
- Text alternatives for images
- Captions for videos
- Color isn't the only visual cue
- Sufficient color contrast
Operable
Interface components must be operable by all users.
Examples:
- Keyboard navigation
- Adequate time to read content
- No seizure-inducing flashing
- Clear navigation
Understandable
Information and interface operation must be understandable.
Examples:
- Readable text
- Predictable behavior
- Input assistance
- Error prevention
Robust
Content must work with current and future technologies.
Examples:
- Valid HTML
- Proper ARIA labels
- Compatibility with assistive technologies
Implementing Accessibility
1. Semantic HTML
Use the right element for the job:
Bad:
<div onClick={handleClick}>Click me</div>
Good:
<button onClick={handleClick}>Click me</button>
Benefits:
- Built-in keyboard support
- Screen reader compatibility
- Proper focus management
2. Keyboard Navigation
Ensure all functionality is keyboard-accessible:
// Tab order
<div tabIndex={0}>Focusable div</div>
// Skip to main content
<a href="#main-content" className="skip-link">
Skip to main content
</a>
// Focus management
useEffect(() => {
if (modalOpen) {
modalRef.current?.focus();
}
}, [modalOpen]);
Test: Navigate your entire site using only Tab, Shift+Tab, Enter, and Space.
3. Color Contrast
Ensure sufficient contrast ratios:
WCAG AA Requirements:
- Normal text: 4.5:1 minimum
- Large text (18pt+): 3:1 minimum
- UI components: 3:1 minimum
Tools:
- WebAIM Contrast Checker
- Chrome DevTools Lighthouse
- Browser extensions (axe, WAVE)
4. Alternative Text
Provide text alternatives for non-text content:
Images:
<!-- Informative image -->
<img src="chart.png" alt="Sales increased 50% in Q4" />
<!-- Decorative image -->
<img src="decorative.png" alt="" />
<!-- Functional image -->
<button>
<img src="search.svg" alt="Search" />
</button>
Complex Images:
<figure>
<img src="complex-diagram.png" alt="System architecture diagram" />
<figcaption>
Detailed description of the system architecture...
</figcaption>
</figure>
5. Form Accessibility
Make forms usable for everyone:
<form>
<label htmlFor="email">
Email Address
<span aria-label="required">*</span>
</label>
<input
type="email"
id="email"
name="email"
required
aria-describedby="email-error"
aria-invalid={hasError}
/>
{hasError && (
<span id="email-error" role="alert">
Please enter a valid email address
</span>
)}
</form>
Best Practices:
- Always use labels
- Group related inputs with fieldset/legend
- Provide clear error messages
- Show validation inline
- Don't rely on placeholder as label
6. ARIA Attributes
Use ARIA when semantic HTML isn't enough:
Roles:
<nav role="navigation">
<ul role="list">
<li role="listitem">...</li>
</ul>
</nav>
States and Properties:
<button
aria-expanded={isOpen}
aria-controls="menu"
>
Menu
</button>
<div
id="menu"
aria-hidden={!isOpen}
role="menu"
>
...
</div>
Live Regions:
<div
role="status"
aria-live="polite"
aria-atomic="true"
>
{statusMessage}
</div>
7. Focus Management
Manage focus for dynamic content:
function Modal({ isOpen, onClose }) {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen) {
// Save current focus
const previousFocus = document.activeElement;
// Move focus to modal
modalRef.current?.focus();
// Trap focus in modal
const handleTab = (e: KeyboardEvent) => {
// Focus trap logic
};
document.addEventListener('keydown', handleTab);
return () => {
// Restore focus
previousFocus?.focus();
document.removeEventListener('keydown', handleTab);
};
}
}, [isOpen]);
return (
<div
ref={modalRef}
role="dialog"
aria-modal="true"
tabIndex={-1}
>
{/* Modal content */}
</div>
);
}
8. Responsive and Mobile Accessibility
Touch Targets: Minimum 44x44 pixels
Zoom: Support up to 200% zoom without horizontal scrolling
Orientation: Support both portrait and landscape
Motion: Provide alternatives to motion-based interactions
Testing for Accessibility
Automated Testing
Tools:
- axe DevTools: Browser extension
- Lighthouse: Chrome DevTools
- WAVE: Online evaluation tool
- Pa11y: Command-line tool
Example with Jest + React Testing Library:
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('should not have accessibility violations', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
Manual Testing
Keyboard Testing:
- Unplug your mouse
- Navigate using Tab, Shift+Tab
- Activate with Enter/Space
- Ensure logical tab order
Screen Reader Testing:
- Mac: VoiceOver (Cmd+F5)
- Windows: NVDA (free) or JAWS
- Mobile: TalkBack (Android) or VoiceOver (iOS)
Color Blindness Simulation: Use browser DevTools or extensions to simulate different types of color blindness
User Testing
Involve users with disabilities in your testing process:
- Recruit diverse testers
- Observe real usage patterns
- Gather feedback early and often
Common Mistakes to Avoid
❌ Using divs for buttons Use semantic button elements instead of divs
❌ Removing focus outlines Style them instead with proper focus styles rather than removing them entirely
❌ Inaccessible modals Trap focus, manage ARIA attributes
❌ Auto-playing media Provide controls, respect user preferences
❌ Relying solely on color Use icons, patterns, or text labels
❌ Time limits without extensions Allow users to extend time or disable limits
❌ Complex CAPTCHAs Use accessible alternatives (reCAPTCHA v3, hCaptcha)
Accessibility Checklist
Page Structure
✅ Proper heading hierarchy (h1-h6) ✅ Landmarks (header, nav, main, footer) ✅ Skip navigation link ✅ Descriptive page titles
Content
✅ Sufficient color contrast ✅ Alt text for images ✅ Transcripts/captions for media ✅ Readable font sizes ✅ Link text describes destination
Interactivity
✅ All functionality keyboard accessible ✅ Visible focus indicators ✅ No keyboard traps ✅ ARIA labels where needed ✅ Form validation messages
Dynamic Content
✅ Live regions for updates ✅ Focus management for modals ✅ Loading states announced ✅ Error messages announced
Resources
Learning
- W3C Web Accessibility Initiative (WAI)
- WebAIM articles and checklists
- A11y Project
- Inclusive Components
Tools
- Browser DevTools
- Screen readers
- Color contrast checkers
- Automated testing tools
Standards
- WCAG 2.1 (current standard)
- Section 508 (US government)
- EN 301 549 (EU standard)
Conclusion
Accessibility is an ongoing process, not a one-time fix. Build it into your development workflow from the start, test regularly, and continuously improve based on user feedback.
The web should work for everyone. Let's make it happen.
Need an accessibility audit or training for your team? Contact us for expert assistance.
Tags
LetsGrow Dev Team
Marketing Technology Experts
