Accessibility (a11y)
WCAG standards, ARIA attributes, and inclusive design practices.
Web Accessibility (a11y)
Accessibility is not a "nice-to-have" feature—it's a fundamental aspect of good web development. Making your applications accessible ensures that everyone, regardless of abilities, can use your products effectively.
WCAG Guidelines
The Web Content Accessibility Guidelines (WCAG) provide the international standard for web accessibility. They're organized around four principles:
Perceivable
Information must be presentable in ways users can perceive.
- Text Alternatives: Provide alt text for images (
alt="Description") - Captions & Transcripts: For video and audio content
- Contrast Ratios:
- WCAG AA: 4.5:1 for normal text, 3:1 for large text
- WCAG AAA: 7:1 for normal text, 4.5:1 for large text
- Responsive Design: Content must remain accessible when zoomed to 200%
Operable
Interface components must be operable.
- Keyboard Navigation: All functionality available via keyboard
- No Keyboard Traps: Users can navigate away from all components
- Focus Management: Clear visible focus indicators
- Time Limits: Give users control over time-sensitive content
Understandable
Information and UI operation must be understandable.
- Readable Text: Use simple language, define abbreviations
- Predictable Navigation: Consistent navigation patterns
- Input Assistance: Help users avoid and correct mistakes
- Error Identification: Clear error messages and suggestions
Robust
Content must be robust enough for various assistive technologies.
- Valid HTML: Proper semantic markup
- ARIA Roles: Use ARIA attributes correctly
- Compatibility: Works with current and future assistive tech
Semantic HTML
The foundation of accessibility is proper HTML structure.
<!-- Bad: Div soup -->
<div class="header">...</div>
<div class="article">...</div>
<div class="button">Click me</div>
<!-- Good: Semantic HTML -->
<header>...</header>
<main>
<article>...</article>
<button>Click me</button>
</main>Essential Semantic Elements
<header>,<nav>,<main>,<footer><section>,<article>,<aside><h1>-<h6>for proper heading hierarchy<button>,<input>,<select>,<textarea>
ARIA Attributes
Accessible Rich Internet Applications (ARIA) enhance semantic HTML when needed.
ARIA Roles
<!-- Landmark roles -->
<div role="banner">...</div> <!-- Header -->
<div role="navigation">...</div> <!-- Nav -->
<div role="main">...</div> <!-- Main -->
<div role="contentinfo">...</div> <!-- Footer -->
<!-- Widget roles -->
<div role="tablist">...</div>
<div role="tabpanel">...</div>
<div role="dialog">...</div>ARIA Properties & States
<!-- Descriptive properties -->
<button aria-label="Close dialog">×</button>
<input aria-describedby="help-text" />
<!-- State indicators -->
<button aria-expanded="false">Menu</button>
<div aria-hidden="true">Hidden content</div>
<input aria-invalid="true" aria-describedby="error-message" />First Rule of ARIA
Don't use ARIA if native HTML elements suffice. Use semantic HTML first, then enhance with ARIA only when necessary.
Keyboard Navigation
Ensure your application is fully keyboard accessible.
Focus Management
/* Visible focus indicator */
button:focus, input:focus, [tabindex]:focus {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
/* Skip to main content link */
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: #0066cc;
color: white;
padding: 8px;
text-decoration: none;
z-index: 1000;
}
.skip-link:focus {
top: 6px;
}Tab Order
// Custom component with proper tab management
function CustomDropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useEffect(() => {
if (isOpen) {
dropdownRef.current?.focus();
}
}, [isOpen]);
return (
<div>
<button
aria-expanded={isOpen}
aria-haspopup="menu"
onClick={() => setIsOpen(!isOpen)}
>
Menu
</button>
{isOpen && (
<ul role="menu" ref={dropdownRef}>
<li role="menuitem"><a href="/item1">Item 1</a></li>
<li role="menuitem"><a href="/item2">Item 2</a></li>
</ul>
)}
</div>
);
}Screen Reader Considerations
Testing with Screen Readers
- VoiceOver (macOS/iOS): Cmd + F5
- NVDA (Windows): Free, popular screen reader
- JAWS (Windows): Commercial, widely used
- TalkBack (Android): Built-in screen reader
Screen Reader Best Practices
- Use heading hierarchy (
<h1>→<h2>→<h3>) - Provide context for links: "Read more about accessibility" vs "Read more"
- Announce dynamic content changes:
aria-live="polite"oraria-live="assertive" - Use landmarks for navigation:
<nav>,<main>,<aside>
// Live region for dynamic content
<div aria-live="polite" aria-atomic="true">
{notification && <p>{notification}</p>}
</div>Testing Tools
Automated Testing
# ESLint with a11y rules
npm install eslint-plugin-jsx-a11y
# React testing with a11y assertions
npm install @testing-library/jest-dom
npm install jest-axe// Unit testing with jest-axe
import { axe, toHaveNoViolations } from 'jest-axe';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';
test('should not have accessibility violations', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});Browser Extensions
- axe DevTools Chrome extension
- WAVE Web Accessibility Evaluation Tool
- Color Contrast Analyzer
- HeadingsMap for heading structure validation
Common Accessibility Issues & Solutions
1. Missing Alt Text
<!-- Bad -->
<img src="chart.png">
<!-- Good -->
<img src="chart.png" alt="Q3 sales increased by 25% compared to Q2">
<img src="decorative-line.png" alt="" role="presentation"> <!-- Decorative -->2. Poor Color Contrast
/* Bad: Low contrast */
.text { color: #999; background: #fff; } /* 3:1 ratio */
/* Good: WCAG AA compliant */
.text { color: #555; background: #fff; } /* 7:1 ratio */3. Forms Without Labels
<!-- Bad -->
<input type="email" placeholder="Email">
<!-- Good -->
<label for="email">Email</label>
<input type="email" id="email" required aria-describedby="email-help">
<div id="email-help">We'll never share your email</div>4. Links Without Context
<!-- Bad -->
<a href="/article">Read more</a>
<!-- Good -->
<a href="/article">Read more about accessibility best practices</a>
<a href="/article" aria-label="Read more about accessibility best practices">Read more</a>Accessibility Checklist
Design Phase
- Color contrast meets WCAG AA standards
- Text remains readable at 200% zoom
- Focus indicators are clearly visible
- Content structure is logical and predictable
Development Phase
- Semantic HTML is used appropriately
- All images have descriptive alt text
- Form inputs have proper labels
- Keyboard navigation works for all interactive elements
- ARIA attributes are used correctly
- Dynamic content changes are announced
Testing Phase
- Test with keyboard only
- Test with screen reader
- Run automated accessibility tests
- Test with mobile accessibility features
- Validate HTML and ARIA implementation
Accessibility is a Team Sport
Accessibility isn't just a frontend responsibility. Designers need to consider color contrast and layout, PMs need to include it in requirements, and QA needs to test with assistive technologies. Everyone plays a role in creating inclusive experiences.