Accessibility

How to design for screen reader users without making everything worse

Most attempts to make interfaces screen-reader-friendly make them harder to use. The fix is to design for both audiences at once.

Designers who care about accessibility tend to discover screen readers late. The discovery usually goes through three phases: realizing screen readers exist, trying to make the interface "screen reader friendly," and then realizing that most of those attempts made the interface worse for everyone, including screen reader users.

The fix isn't to design a separate experience for assistive technology. It's to understand how screen readers expose interfaces, and to design once for both audiences.

What a screen reader actually does

A screen reader reads the accessibility tree, which is a parallel representation of the page generated from the DOM, ARIA attributes, and platform conventions. The user navigates this tree using keyboard shortcuts that move by element, by heading, by landmark, by form control, by link. They can also linearize the page and read it top to bottom.

That last detail matters most. A sighted user scans the visual hierarchy and jumps to what they need. A screen reader user navigates by structure. By the labels and relationships you encoded into the markup. If the structure is wrong, no amount of visual polish helps them.

This is why semantic HTML matters more than ARIA. A heading element is a navigation target. A <div> styled to look like a heading is not. A <button> announces itself as a button. A <div role="button"> announces itself as a button but requires you to manually wire up everything the native element gives you for free, and you will miss something.

The common mistakes that hurt screen reader users

Adding aria-label everywhere. A button with visible text "Save" and an aria-label of "Save changes to your profile" announces as "Save changes to your profile, button." The visible text is overridden. Now the visual user and the screen reader user are hearing different things, which makes support conversations confusing.

Using aria-hidden on visible content to remove it from screen readers. There's usually a real reason something is being hidden: duplication, decoration, redundancy. But aria-hidden on focusable elements is broken behavior: the user can tab to an element they can't hear. If something should be hidden, hide it with display: none or remove it from the tab order entirely.

Using "click here" or "read more" link text. Screen reader users often pull up a list of all links on a page to navigate. A list of fifteen "read more" links tells them nothing. The link text should describe the destination on its own. "Read the full report" or "Continue to checkout" works in context and out of context.

The structural choices that actually help

Heading hierarchy is the single most useful thing you can get right. Screen reader users navigate by heading more than any other element. A page with a clean h1-h2-h3 structure, with no skipped levels and no headings used purely for visual size, is navigable without further work. A page with semantic chaos in the headings is impenetrable.

Landmarks are the second-most-useful piece. The elements <main>, <nav>, <aside>, and <footer> create jump targets that let users skip the parts they don't care about. A site that wraps everything in <div>s forces screen reader users to read or skip linearly with no shortcuts.

Form labels matter, but the trap is the implementation. A <label> associated to an input via for/id is unambiguous. A label rendered as text near an input but not associated is invisible to screen readers. The visual association doesn't transfer.

Live regions and dynamic content

This is where designs most often fail invisibly. A toast that appears, a form error that updates, a filter result count that changes. These are visual feedback that screen reader users miss entirely unless the dynamic content is announced.

The aria-live attribute handles this, but it's easy to misuse. aria-live="polite" announces changes when the user is idle. aria-live="assertive" interrupts whatever the user is doing, which should be reserved for critical information like errors. Designers often don't know this distinction exists, which means engineers make the call, which means it's inconsistent across the product.

The design decision here isn't technical. It's about which dynamic changes are important enough to interrupt. That's a design question, and it should be answered at design time, not discovered at QA.

Testing without an audit

You don't need a formal audit to learn what your product sounds like. Turn on VoiceOver on macOS or NVDA on Windows, close your eyes, and try to do something. The first time you do this you'll find five things in five minutes: unlabeled buttons, broken focus order, regions that announce confusingly.

This isn't a substitute for testing with actual screen reader users, who use the technology fluently in ways you won't. But it gets you past the worst issues without involving anyone else. And it changes how you design the next thing, because once you've heard your own product, you stop building interfaces that can't speak.

Greg Sargent
Greg SargentDirector of Design Systems, Spring Health

I write about design systems, accessibility, and the way AI is changing how we build software.

Published December 15, 2025

Be the first to rate this article.