Skip to content

A screen reader turns what's on the screen into speech or braille. People who are blind or have low vision use one to shop, bank, read, and work. It mostly says what the code tells it, so when the code is wrong, people hear the wrong thing, or not enough to go on. Here's where that happens most, and how to fix it.

Close your eyes and try to buy something online. You'd need someone to read you the page, tell you what each thing is, and let you skip around instead of hearing everything from the top. That's a screen reader.

It reads the page's structure: headings, links, buttons, form labels, and the text behind images. Most people don't listen top to bottom. They jump from heading to heading, pull up a list of every link, or move field by field through a form, often with the speech turned up faster than most of us could follow.

Some people read with a refreshable braille display, alongside speech or instead of it. Either way, if something only makes sense visually, it doesn't come through.

Common tools

JAWS
Windows. Paid, and the most widely used.
NVDA
Windows. Free and open source.
Narrator
Built into Windows.
VoiceOver
Built into Mac, iPhone, and iPad.
TalkBack
Built into Android.

Most of these are small changes in the code. Where WCAG covers one, we link the success criteria it falls under.

  1. Buttons and links with no name

    Icon buttons for search, the cart, or the menu look obvious on screen. In the code, many have no text at all, so the screen reader says "button" and nothing else. Links that say "Click here" or "Read more" make no sense when someone pulls up a list of every link on the page, and fail outright when nothing around them says where they go.

    What a screen reader says
    Now
    “Button”
    Fixed
    “Search, button”

    The fix

    Give every control a name that says what it does. Visible text is best. For an icon-only button, add an aria-label and hide the icon itself. For links, use words that make sense on their own, like "Read the shipping policy."

    Before
    <button type="button">
      <svg>…</svg>
    </button>
    After
    <button type="button" aria-label="Search">
      <svg aria-hidden="true">…</svg>
    </button>
  2. Images with missing or unhelpful alt text

    Without alt text, the screen reader falls back on whatever it can find, often the file name. Product photos, charts, and images with words in them carry real information, and all of it is lost. Decorative images that do get described just add noise.

    What a screen reader says
    Now
    “IMG_4032.jpg, image”
    Fixed
    “Navy wool coat, front view, image”

    The fix

    Describe what the image is there to show, in a short phrase. Skip "image of," since the screen reader already says it's an image. If an image is only decoration, give it an empty alt so it's skipped.

    Example
    <img src="coat.jpg" alt="Navy wool coat, front view">
    <img src="divider.svg" alt="">
  3. Headings that only look like headings

    Jumping between headings is how most screen reader users find what they need on a long page, about 7 in 10 in WebAIM's survey. Big, bold text coded as a plain paragraph or div doesn't show up in that list, so whole sections get skipped. Headings that skip levels at random make the outline hard to follow.

    WebAIM's survey of screen reader users

    The fix

    Use real heading tags, h1 through h6, for every section title, in order: one h1 for the page, h2 for its sections, h3 for what's inside them. Style them however you like with CSS.

    Before
    <div class="section-title">Shipping</div>
    After
    <h2 class="section-title">Shipping</h2>
  4. Form fields without labels

    A label that isn't connected to its field in the code gets announced as "edit text." Was that the email or the phone number? Placeholder text is a weak stand-in, since it disappears as soon as someone starts typing. Error messages that only turn a border red, or show up somewhere else on the page, leave people guessing what went wrong.

    What a screen reader says
    Now
    “Edit text”
    Fixed
    “Email, required, edit text”

    The fix

    Connect a visible label to every field with for and id. Mark required fields in the code, not only with an asterisk. When a field has an error, set aria-invalid="true" and tie the message to the field with aria-describedby, so it's read along with the field.

    Example
    <label for="email">Email</label>
    <input id="email" type="email" required
      aria-invalid="true" aria-describedby="email-error">
    <p id="email-error">Enter an email like name@example.com.</p>
  5. Custom controls that don't say what they are

    Dropdowns, toggles, tabs, and accordions built from plain divs look right but say nothing. The screen reader reads the text and stops there. Is it a button? Is it open or closed? Is the switch on? The person has to guess, and often can't operate it at all.

    What a screen reader says
    Now
    “Shipping options”
    Fixed
    “Shipping options, collapsed, button”

    The fix

    Start with native HTML. A button, select, or checkbox already tells the screen reader what it is and what state it's in. When a custom control is the only option, add the right role, make it reachable and usable from the keyboard, and keep its state current with attributes like aria-expanded, aria-pressed, or aria-checked.

    Example
    <button type="button" aria-expanded="false"
      aria-controls="shipping">
      Shipping options
    </button>
  6. Changes that happen silently

    Someone presses "Add to cart." A badge on the cart icon changes, and that's it. Search results load, a filter updates the list, or an error appears at the top of the form, and the screen reader says nothing. From their side, the button didn't work.

    What a screen reader says
    Now
    “(silence)”
    Fixed
    “Added to cart. 2 items in your cart.”

    The fix

    Announce updates that don't move focus with a live region, like an element with role="status". The region has to be on the page before the message goes into it, or it may not be read. For bigger changes, like the next step of checkout, move focus to the new content's heading (give it tabindex="-1" so it can take focus).

    Example
    <div role="status" id="cart-status"></div>
    
    // After the item is added:
    document.querySelector('#cart-status').textContent =
      'Added to cart. 2 items in your cart.'
  7. Pop-ups the screen reader wanders out of

    A dialog opens over the page, but focus stays behind it. The screen reader keeps reading the page underneath, which sighted users see dimmed and out of reach, and the person may never find the dialog. When it closes, focus often lands back at the top of the page.

    The fix

    Move focus into the dialog when it opens, keep it there while it's open, and return it to the button that opened it when it closes. The native dialog element, opened with showModal(), handles most of this for you. Give the dialog a name with aria-labelledby pointing at its heading.

    Example
    const dialog = document.querySelector('dialog')
    // Moves focus in and makes the page behind inert.
    dialog.showModal()

Every computer and phone you own already has a screen reader. Ten minutes with one will show you more than a checklist can.

  • Mac

    Press Command + F5 to start VoiceOver. Press Control + Option + Right Arrow to move to the next item, and Control + Option + U to open the rotor, a list of headings, links, and form fields. Use the arrow keys to switch lists. Press Command + F5 again to turn it off.

  • Windows

    Narrator is built in: press Windows + Control + Enter to turn it on or off. For a closer match to what most people use, download NVDA for free from nvaccess.org. Press H to jump between headings, Tab to move through controls, and Insert + F7 for a list of every link and heading. Press Control any time to stop it talking.

  • iPhone

    Set up the Accessibility Shortcut first, in Settings > Accessibility > Accessibility Shortcut, and pick VoiceOver. Then a triple-click of the side button (or Home button) turns it on and off. With it on, swipe right to move to the next item and double-tap to press it.

  • Listen for

    Does every button say what it does? Can you find each section by heading? Does the form tell you what each field is, and what went wrong? Do you hear anything when the page changes?

Go easy on yourself. You'll be slow at first, and people who use a screen reader every day are much faster. But if something has no name or makes no sound, it's broken for them too.

We're collecting stories from people who use assistive tech every day. Yours can help the people who build websites and apps see what gets in the way.

To know the road ahead, ask those coming back. We test with the same tools your users do.

No prep, no formal brief. A few sentences is plenty. Let us know what you're building and we'll take it from there. We typically respond within one business day.