About one in six people worldwide has a disability affecting how they use the web. This lesson covers the foundational accessibility principles every React component should follow: semantic HTML, meaningful alt text, never relying on color alone, and testing with real assistive technology.
1Accessibility Isn't a Feature You Add Later
Roughly one in six people worldwide has a disability affecting how they use the web, whether through a screen reader, keyboard-only navigation, or assistive zoom. Building accessible components from the start is building components that genuinely work for everyone using them, not an optional add-on.
2Semantic HTML Is Your First Line of Defense
A div styled to look like a button provides none of a real button's built-in behavior — keyboard focus, Enter/Space activation, correct screen reader announcement. Using the correct native HTML element is almost always less work and more accessible than recreating that behavior manually.
3Images Need Meaningful alt Text
Every informative image needs alt text describing what it actually conveys, not its filename or a generic placeholder. Purely decorative images with no informational value should use alt="" so screen readers correctly skip over them.
4Color Alone Should Never Carry Meaning
A form field that only changes color to indicate an error is invisible to colorblind users and provides no signal to screen reader users. Pairing color with a second signal — an icon, text, an underline — ensures the meaning survives regardless of whether the color itself is perceived.
5Test with a Real Screen Reader, Not Just DevTools
Automated accessibility linters catch a meaningful set of issues, like missing alt text or invalid ARIA, but miss awkward reading order and confusing announcements. Actually navigating a component with a real screen reader like VoiceOver or NVDA surfaces problems no linter can detect.
6Step-by-Step Breakdown
Accessibility Isn't a Feature You Add Later. About 1 in 6 people worldwide has a disability affecting how they use the web — a screen reader user, someone navigating by keyboard only, someone with low vision using high zoom. Building accessible components from the start isn't extra work bolted on; it's building components that actually work for everyone using them.
Semantic HTML Is Your First Line of Defense. A <div onClick={...}> styled to look like a button gives you none of a real <button>'s built-in behavior — keyboard focus, Enter/Space activation, correct screen reader announcement. Using the right native HTML element is almost always less work AND more accessible than recreating that behavior yourself.
Why does <div onClick={handleClick}>Submit</div> fail keyboard users, while <button onClick={handleClick}>Submit</button> doesn't?
- →A div has no built-in keyboard focus or Enter/Space activation, unlike a real button
- →It's purely a styling issue, unrelated to keyboard usage
Images Need Meaningful alt Text. Every meaningful <img> needs an alt describing what it conveys — not the filename, not 'image', but what a sighted user actually understands from looking at it. Purely decorative images (a background flourish with no informational value) should have alt="" so screen readers skip them entirely.
Color Alone Should Never Carry Meaning. A form field that turns red on error, with no icon or text change, is invisible to a colorblind user or anyone with a screen reader. Always pair color with a second signal — an icon, a text label, an underline — so the meaning survives even if the color itself doesn't come through.
Why is a form field that only turns red on error, with no icon or text, an accessibility problem?
- →It relies on color as the only signal, invisible to colorblind users and screen readers
- →Changing border color is too slow a CSS operation
Test with a Real Screen Reader, Not Just DevTools. Automated accessibility linters (like eslint-plugin-jsx-a11y) catch a meaningful chunk of issues but miss plenty — awkward reading order, confusing announcements, missing context. Actually navigating your own component with VoiceOver (Mac), NVDA (Windows, free), or a screen reader emulator surfaces problems no linter will ever find.
Mastery Achieved. You now have a foundation for accessible components: reaching for semantic HTML first, meaningful (or intentionally empty) alt text, never relying on color alone, and verifying with real assistive technology, not just automated linters. Next, you'll apply these principles specifically to forms.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Pairs well with ChromeVox or NVDA (Windows) for accessibility testing.
Fully supported; pairs with NVDA on Windows.
Pairs with the built-in VoiceOver screen reader on macOS.
Fully supported.
Accessibility (A11y)
1Prefer Native Elements Over ARIA-Patched Divs
The first rule of ARIA is: don't use ARIA if a native HTML element already provides the needed semantics and behavior — reach for <button>, <a>, <input>, and similar elements before reaching for role attributes on a generic div.
2Decorative Images Must Use an Explicitly Empty alt
Omitting the alt attribute entirely on a decorative image can cause some screen readers to announce the filename instead — always include alt="" explicitly for purely decorative images.
SEO Implications
- 1
Meaningful alt Text Also Benefits Image Search Indexing
Descriptive alt attributes serve both accessibility and SEO simultaneously, since search engines use alt text to understand and index image content.
Best Practices
Default to Semantic HTML Before Reaching for ARIA
A correctly used native element (button, nav, main, label) provides accessible behavior automatically — only add ARIA attributes when semantic HTML genuinely can't express what's needed.
Run an Automated Linter as a First Pass, Real Testing as the Real Check
Use eslint-plugin-jsx-a11y (or similar) to catch obvious mistakes early in development, but treat it as a floor, not a ceiling — genuine screen reader testing remains necessary before shipping significant UI.
Frequent Bugs
A custom clickable div-based 'button' can't be activated with the keyboard.
Replace it with a real <button> element, which provides keyboard focus and Enter/Space activation automatically, instead of trying to manually recreate that behavior with tabIndex and onKeyDown handlers.
A decorative background image is announced by a screen reader with a confusing filename like 'hero-bg-final2.png'.
Add alt="" explicitly to the image, signaling it's purely decorative so screen readers skip it entirely instead of announcing the filename.
Real-World Examples
Converting a Div-Based Toggle to a Real Button
A dark mode toggle was originally built as a styled <div onClick={toggleTheme}>, which worked visually but was completely unusable via keyboard and wasn't announced correctly by screen readers. Replacing it with <button onClick={toggleTheme} aria-pressed={isDark}> fixed both issues immediately, with less code overall.
// Before
<div onClick={toggleTheme} className="toggle">🌙</div>
// After
<button onClick={toggleTheme} aria-pressed={isDark} className="toggle">🌙</button>