The Tension
Most product teams operate in a tension they don't talk about: screen reader users need semantic HTML structure; sighted users need visual hierarchy. Sometimes these align perfectly. Sometimes they diverge completely.
A screen reader user needs to understand the page structure by headings. So you mark up your navigation bar with proper semantic HTML: nav, ul, li, a. A sighted user needs to see the navigation visually on the page. So you style it with CSS to look like a horizontal bar. These requirements are compatible.
But consider a more complex case: a data table with expandable rows. A sighted user needs to see rows collapse and expand with a visual cue. A screen reader user needs to understand the table structure semantically (which rows are nested, what the relationships are). The visual structure and the semantic structure don't automatically match. You have to make deliberate choices.
This is where ARIA comes in. ARIA (Accessible Rich Internet Applications) is a bridge layer that lets you add semantic information to the page that's invisible to sighted users but meaningful to assistive technologies. It's powerful. It's also easy to misuse.
Where ARIA Genuinely Helps
ARIA is most useful when native HTML can't express the semantics you need. Here are cases where ARIA genuinely fills a gap:
- Icon buttons with aria-label. A button with just a magnifying glass icon has no accessible name. A screen reader user hears nothing. Adding
aria-label="Search"solves this. The sighted user still sees the icon. The screen reader user gets a label. This is exactly what ARIA is for. - Accordions with aria-expanded. An accordion button needs to communicate whether its panel is open or closed. HTML has no native way to express this.
aria-expanded="true|false"tells screen reader users the state. Sighted users see the visual state. Both needs met. - Live regions with aria-live. When dynamic content appears on the page (a notification, an error message, search results appearing), a sighted user sees it immediately. A screen reader user won't unless you announce it.
aria-live="polite"oraria-live="assertive"makes the screen reader announce changes. This is necessary. - Modals with role="dialog" and focus management. A modal dialog is more than a div on top of the page. Screen reader users need to know they're in a special context.
role="dialog"helps. But more importantly, focus needs to move into the modal and trap there. When the modal closes, focus needs to return to the trigger. This requires both ARIA and JavaScript. It's complex but necessary.
Notice the pattern: in each case, HTML alone can't communicate the full semantic meaning. ARIA fills the gap. And in each case, the ARIA is helping the screen reader user without hurting the sighted user.
Where ARIA Gets in the Way
ARIA becomes a problem when it's used carelessly or excessively. Here are common mistakes:
- Over-announcing. Adding aria-label to everything, including decorative elements. A designer adds
<svg aria-label="Heart icon" role="img">to a decorative heart. The heart is already visual. Now a screen reader user hears "Heart icon" when they don't care. Worse, they hear it multiple times as they navigate. The solution: let the heart be decorative. Usearia-hidden="true"on it instead. - Hiding important content with aria-hidden. A team uses
aria-hidden="true"to hide content from screen readers. But the content is actually important. A disabled state on a button might be visually obvious to a sighted user. But a screen reader user navigating to that button needs to know it's disabled. Hiding it with aria-hidden makes it disappear from the screen reader entirely. Instead, use a proper disabled state on the button element. - Using aria-label when HTML is better.
<div role="button">Click me</div>with an aria-label is wrong. Use<button>Click me</button>instead. Native button elements come with keyboard support and screen reader semantics built in. When you use a div with role="button" and aria-label, you have to reinvent all of that. It's more work and more error-prone. - Aria-live on too many elements.
aria-live="assertive"tells screen readers to announce changes immediately, interrupting whatever the user is doing. Use it sparingly: only for truly urgent announcements. If you put aria-live on search results or every status message, the screen reader becomes noisy and annoying. Screen reader users will turn it off.
The meta-problem: these mistakes happen because teams don't test with real screen reader users. They add ARIA based on what they think is correct, not based on how it actually sounds to a screen reader user.
Visually Hidden Text
There's a subtle but important pattern called "visually hidden text." It's the opposite of aria-hidden. Instead of hiding text from screen readers, you hide it from sighted users.
The common pattern uses a CSS class (often called sr-only for "screen reader only"):
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
This CSS completely removes the element from the visual layout but keeps it in the DOM so screen readers can access it. When is this useful? Consider a "Previous" button in article navigation. A sighted user sees "Previous" and the visual context makes it clear. A screen reader user just hears "Previous": which previous? Previous article? Previous section?
The solution: add visually hidden text:
<a href="..." class="article-nav-btn prev">
<span class="sr-only">Previous article: </span>
Previous
</a>
Now the screen reader announces "Previous article: Why Accessibility Fails at Design." The sighted user still sees just "Previous" with styling that makes it clear it's a navigation button.
The risk: it's easy to hide too much or too little. Some teams hide entire sections of content from sighted users when they shouldn't. The principle is simple: use sr-only to add context that helps screen reader users without cluttering the visual design for sighted users.
Testing Both Experiences
The real test is this: walk through your page twice. First time, use a screen reader (NVDA on Windows, VoiceOver on Mac, or both). Don't look at the screen. Just listen. Does the page make sense? Can you navigate? Do you understand the structure and the purpose of buttons and links?
Second time, use keyboard navigation only (no mouse). Tab through the page. Does focus move logically? Can you reach all interactive elements? Can you dismiss modals? Can you navigate menus? Do focus indicators appear?
Third time, look at the page with your eyes. Does it look correct? Are visual states (hover, focus, active, disabled) clear?
If all three experiences work, you've found the balance. If one breaks in service of another, that's a signal that something needs adjustment. Maybe you need more ARIA. Maybe you need to change the HTML structure. Maybe you need to adjust the visual design. But it's only by testing all three that you can see the tension and make an informed choice.