A Developer’s Guide to Web Accessibility with HTML and React

I remember building fast, modern interfaces and realizing that performance alone wasn’t enough; accessibility was the missing layer. A website can look flawless and still exclude users who rely on screen readers, keyboard navigation, or assistive technology.
Web accessibility is not an optional enhancement; it is a foundational engineering decision. It ensures that semantic structure, ARIA usage, and interaction patterns work consistently across browsers, devices, and assistive tools.
In this guide, I’ll break down how to apply semantic HTML correctly, when ARIA is appropriate, and how to implement accessibility properly in React, without overengineering or adding unnecessary complexity.

What is Semantic HTML?
Semantic HTML means using HTML tags that describe the content's meaning, not just its appearance. These tags tell browsers and assistive technologies what kind of content they’re interacting with, making your website more meaningful, especially for people using screen readers.
Good for screen readers, SEO, and other tools to understand your layout.
Common Semantic Elements and When to Use Them
| Tag | Use For | Example |
<header> | Page or section header | Top section of page |
<nav> | Navigation links | Menus or link bars |
<main> | Main content (1 per page) | Article, dashboard, etc. |
<section> | Thematic grouping | Features, Services |
<article> | Self-contained content | Blog post, comment |
<aside> | Secondary content | Sidebars, ads, notes |
<footer> | Page or section footer | Copyright, contact |
<h1> to <h6> | Headings (semantic levels) | Titles and subtitles |
<ul>, <ol>, <li> | Lists | FAQs, features |
<form> | Group of input fields | Sign-up or search |
<label> | Label for form field | Name, Email |
<button> | Clickable actions | Submit, Next |
<a> | Navigation links | Internal or external |
Use Semantic HTML First and Always
Start with HTML that means something. Don’t use a <div> or <span> just because it works visually use a <button> if it’s clickable, a <nav> if it’s navigation, and so on.
Why?
- Built-in accessibility
- Keyboard support (like Tab and Enter)
- Clear structure for screen readers
Example
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<section>
<h2>Features</h2>
<p>Explore powerful tools.</p>
</section>
</main>
<footer>
<p>© 2025</p>
</footer>Use ARIA When HTML Alone Isn't Enough
ARIA stands for Accessible Rich Internet Applications. It allows you to fill in accessibility gaps when you're building custom UI components that native HTML doesn’t support well (like custom modals, tabs, dropdowns, etc.)
When to use ARIA
- You build a non-native interactive component
- You want to improve screen reader output
- You're updating content dynamically (e.g., live region)
| Aria Attribute | Use case |
aria-label | Label for element with no visible text |
aria-hidden=”true” | Hide from screen readers |
aria-live | Announce dynamic content updates |
aria-expanded | Toggled state (dropdowns, accordions) |
aria-controls | Describes what element is controlled |
role=”dialog” | Custom modals |
role=”tablist”, role=”tab” | Custom tab interfaces |
Example
<button aria-expanded="false" aria-controls="dropdown1">Menu</button>
<ul id="dropdown1" hidden>
<li>Item 1</li>
</ul>When to avoid ARIA?
ARIA is powerful, but it can cause more harm than good if misused. You should avoid ARIA:
- When a semantic HTML element can do the job. Use <button> instead of <div role="button">.
- If you’re not also implementing keyboard interaction. ARIA doesn’t add keyboard behavior.
- When you don’t fully test it with screen readers or assistive tech. Poor ARIA usage can confuse users.
- If it makes the DOM more complex without a clear benefit.
Example of What Not to Do:
<!-- Avoid this -->
<div role="button">Click me</div>This lacks keyboard support, focus, and built-in accessibility.
Correct Semantic Version:
<button>Click me</button>Use aria-labelledby to Replace or Combine Labels
Sometimes the visible label for an element comes from another part of the page. Use ‘aria-labelledby’ to associate it.
Let’s Build an Accessible Web Together!
We design and develop web experiences that everyone can use, simple, inclusive, and ADA-compliant.
Example:
<div role="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Subscribe</h2>
<p>Sign up for weekly updates.</p>
</div>Use aria-describedby for Help Text, Errors, or Hints
This is helpful when you want to add supporting context, like form hints or validation messages.
Example:
<label for="email">Email</label>
<input id="email" aria-describedby="email-hint email-error" />
<p id="email-hint">We'll never share your email.</p>
<p id="email-error" style="color:red;">Email is required.</p>Screen readers will read: “Email. We’ll never share your email. Email is required.”
Comparing Accessible and Inaccessible HTML Code in Practice
Sometimes seeing the difference makes it click. Here are the examples of accessible vs. non-accessible code:
Inaccessible Button Example
<div onclick="submitForm()">Submit</div>No role or semantics
Not keyboard accessible
Accessible Button Example
<button onclick="submitForm()">Submit</button>Screen reader-friendly
Built-in keyboard support
Inaccessible Form Input
<input type="text" placeholder="Your Name">No label for screen readers
Accessible Form Input
<label for="name">Name</label>
<input type="text" id="name">Proper label association
Accessibility in React Apps
React developers need to consider a few extra steps:
Use ‘htmlFor’ instead of ‘for’ in labels:
<label htmlFor="email">Email</label>
<input id="email" type="email" />Manage keyboard events on custom components:
<div role="button" tabIndex={0} onKeyDown={handleKeyDown} onClick={handleClick}>
Toggle
</div>Use ‘aria-live’ for dynamically changing content:
<div aria-live="polite">{message}</div>Consider accessible libraries like @radix-ui/react-*, reach-ui, or react-aria.
Let’s Build an Accessible Web Together!
We design and develop web experiences that everyone can use, simple, inclusive, and ADA-compliant.
While building or auditing your React components, studying a thorough Competitive analysis for UX can also reveal patterns in how others solve similar accessibility challenges, helping you benchmark your approach.
How Users Experience Your Site Without Accessibility
Accessibility decisions directly impact how users interact with your product. When semantic structure is missing, screen readers fail to interpret intent. When keyboard focus is unmanaged, navigation breaks. When ARIA is misused, assistive technology produces misleading output.
Engineering accessible interfaces prevents these structural failures before they affect real users.
"I couldn't find the checkout button on your site. I had to ask a friend to help."
Or someone with color blindness:
"I didn’t realize the red box meant an error. There was no text or icon."
Designing with accessibility in mind makes sure everyone can access what you’ve built.
When to Use Semantic HTML vs ARIA?
| Goal | Use |
Basic structure and meaning | Semantic HTML |
Label an element (no text) | aria-label or aria-labelledby |
Add extra instructions | aria-describedby |
Dynamic or custom elements | ARIA roles/attributes |
Hide decorative content | aria-hidden="true" |
This kind of decision-making is similar to how developers weigh LLM fine tuning vs RAG, where each method has its own strengths depending on the problem you’re solving.
Frequently Asked Questions (FAQ)
1. Why is semantic HTML important for accessibility?
Semantic HTML provides built-in meaning, keyboard behavior, and screen reader compatibility, reducing the need for ARIA and improving SEO structure.
2. When should ARIA be used instead of semantic HTML?
ARIA should only be used when native HTML elements cannot provide required behavior, such as custom dialogs, tabs, or dynamic components.
3. Does React handle accessibility automatically?
React does not automatically make components accessible. Developers must manage focus states, keyboard events, ARIA attributes, and proper labeling.
4. What is the difference between aria-labelledby and aria-describedby?
aria-labelledby defines the accessible name of an element, while aria-describedby adds supplementary context such as hints or error messages.
5. Is accessibility good for SEO?
Yes. Proper semantic structure improves crawlability, content hierarchy, and search engine understanding.
Conclusion
Accessibility is an engineering discipline, not a finishing step. By prioritizing semantic HTML, applying ARIA only when necessary, and validating interactions with real assistive tools, developers create systems that scale reliably across users and environments.
Inclusive design improves usability, SEO structure, legal compliance, and long-term maintainability. The goal is not complexity, it is clarity. And clarity in structure always improves accessibility. What matters is the intention to include, the willingness to learn, and the small steps taken consistently.



