Web accessibility is no longer a bonus: it's a legal requirement in many countries and above all an ethical issue. Yet too many developers still consider a11y as a constraint. Here's how to integrate it naturally into your workflow.
Why Accessibility Matters
15% of the world's population lives with a disability. Ignoring accessibility means excluding millions of potential users from your applications.
Good accessibility practices improve the experience for everyone: keyboard navigation, readable contrasts, and semantic structure benefit every user.
SEO and accessibility are linked. Google values well-structured sites with alternative content for images and clear heading hierarchy.
WCAG 2.2 Basics
WCAG (Web Content Accessibility Guidelines) defines 4 principles: Perceivable, Operable, Understandable, Robust. Each criterion has 3 levels: A, AA, AAA.
Aim for AA level minimum. This includes: 4.5:1 contrast ratios for text, complete keyboard navigation, alt text for images, and labels for forms.
WCAG 2.2 (2023) adds important criteria: minimum touch target size (24x24 CSS pixels), accessible authentication, and consistent contextual help.
Semantic HTML: Your First Tool
Use the right HTML elements. A <button> is keyboard-clickable and correctly announced by screen readers. A <div onClick> is not.
Structure with <header>, <main>, <nav>, <article>, <aside>, <footer>. These landmarks allow assistive technology users to navigate quickly.
Respect heading hierarchy. One <h1> per page, then <h2>, <h3>... without skipping levels. It's your content outline.
<!-- ❌ Bad: inaccessible div soup -->
<div class="header">
<div class="nav">...</div>
</div>
<div class="content">
<div class="title">My title</div>
</div>
<!-- ✅ Good: semantic HTML -->
<header>
<nav aria-label="Main navigation">...</nav>
</header>
<main>
<h1>My title</h1>
</main>ARIA: When and How to Use It
ARIA (Accessible Rich Internet Applications) complements HTML when native elements aren't enough. Golden rule: only use ARIA if necessary.
Common roles: role='button' for a non-button interactive element, role='alert' for urgent messages, role='dialog' for modals.
aria-label and aria-labelledby name elements. aria-describedby adds a description. aria-live announces dynamic changes.
// Accessible component with ARIA
function SearchInput() {
const [results, setResults] = useState([]);
return (
<div>
<label htmlFor="search">Search</label>
<input
id="search"
type="search"
aria-describedby="search-hint"
aria-controls="search-results"
/>
<p id="search-hint" className="sr-only">
Type at least 3 characters
</p>
<ul
id="search-results"
role="listbox"
aria-live="polite"
>
{results.map(r => (
<li key={r.id} role="option">{r.title}</li>
))}
</ul>
</div>
);
}Testing and Tools
Integrate accessibility tests into your CI. axe-core with jest-axe or Playwright automatically detects common violations.
Test manually with keyboard: Tab to navigate, Enter/Space to activate, Escape to close. If you're stuck, your users will be too.
Use a screen reader. VoiceOver (Mac), NVDA (Windows free) or TalkBack (Android). 30 minutes of testing reveals issues that automated tools miss.
Conclusion
Accessibility isn't a feature you add at the end. It's a development approach that benefits everyone. Start with semantic HTML, test with keyboard, and improve progressively. Every improvement counts.