All articles
  • Accessibility
  • Frontend

Designing for Accessibility: Beyond the Basics

You've added alt text and checked your contrast. Great. Here's the next layer: the practical stuff that actually makes interfaces usable for everyone.

• 5 min read

Illustration of a confirmation dialog with a visible focus ring, keyboard keys, a screen reader announcement and a contrast score

Most of us know the accessibility basics by now. Add alt text to images. Make sure text has enough contrast. Maybe run Lighthouse and feel good about the green score.

Those things matter. But I’ve seen plenty of sites with a perfect Lighthouse accessibility score that are still painful to use with a keyboard or screen reader. Automated tools catch only a slice of real issues. The rest you have to find by actually using your product the way your users do.

So let’s go a level deeper. Here’s what I check, and how.

Try the “unplug your mouse” test

This is the single most useful accessibility test I know, and it costs nothing. Put your mouse aside and try to use your site with just the keyboard:

  • Tab to move forward, Shift + Tab to go back
  • Enter to activate links and buttons
  • Space to toggle checkboxes and buttons
  • Arrow keys inside menus, radio groups and tabs
  • Escape to close things

Ask yourself as you go:

  1. Can I see where I am? If the focus indicator disappears, you’ve got a problem.
  2. Can I reach everything? Every button, link, menu item and form field.
  3. Does the order make sense? Focus should follow the visual reading order.
  4. Can I get out? Modals and menus should close with Escape and not trap you forever.

You’ll almost certainly find something. Everyone does.

Never remove focus styles. Improve them.

This line of CSS has caused more accessibility harm than almost anything else:

/* Please don't */
*:focus { outline: none; }

People remove focus outlines because they think they look ugly when you click a button. The good news is you don’t have to choose. :focus-visible shows the outline for keyboard users but not mouse clicks:

:focus-visible {
  outline: 2px solid var(--color-action-primary);
  outline-offset: 3px;
}

Designers get clean mouse interactions, keyboard users get a clear indicator. Everyone wins.

Use the right element (it does half the work)

So much accessibility work is just undoing the damage of using the wrong HTML element. The classic:

<!-- Looks like a button, isn't one -->
<div class="btn" onclick="save()">Save</div>

<!-- Is a button -->
<button type="button" onclick="save()">Save</button>

The <div> version can’t be focused with Tab, doesn’t respond to Enter or Space, and a screen reader won’t announce it as a button. To fix it you’d need tabindex, role, and keyboard handlers. Or you could just use <button> and get all of that for free.

A good rule of thumb:

  • Goes somewhere? Use <a href>.
  • Does something? Use <button>.

Every input needs a real label

Placeholders aren’t labels. They disappear when you start typing, they’re often low contrast, and some screen readers handle them inconsistently.

<!-- Not enough -->
<input type="email" placeholder="Email" />

<!-- Good -->
<label for="email">Email address</label>
<input id="email" type="email" autocomplete="email" />

Bonus: clicking a properly connected label focuses the input, which gives everyone a bigger tap target on mobile.

Icon buttons need names

That little hamburger menu or trash-can icon? To a screen reader, it might be announced as just “button,” which is useless. Give it a name:

<button type="button" aria-label="Delete invoice">
  <svg aria-hidden="true">...</svg>
</button>

Note the aria-hidden on the SVG so the icon itself isn’t read out as noise.

Announce things that change

When something updates on the page without a page load, like a “Saved!” toast, a form error or a cart count, sighted users see it. Screen reader users might have no idea it happened.

A live region fixes that:

<div aria-live="polite" class="sr-only" id="status"></div>
document.getElementById("status").textContent = "Changes saved";

Anything you put in that element gets read out. Use polite for most things so it waits for the screen reader to finish what it’s saying. Save assertive for genuinely urgent stuff.

Respect motion preferences

Some people get dizzy or nauseous from large animations. Operating systems have a “reduce motion” setting, and CSS can read it:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

You don’t need to remove all motion, just tone down the big parallax and sliding stuff.

Actually try a screen reader

It’s intimidating the first time, but give it 15 minutes. If you’re on a Mac, VoiceOver is built in: press Cmd + F5 to turn it on. On Windows, NVDA is free.

Navigate your site with it. Try filling in a form. You’ll quickly notice things like:

  • Images announced as “IMG_2847.jpg”
  • Links that all just say “click here” or “read more”
  • Headings that skip levels, making the page structure confusing

It’s genuinely eye-opening, and it makes accessibility feel a lot less abstract.

Write for humans too

Accessibility isn’t only about assistive tech. Clear writing helps people with cognitive differences, people reading in a second language, and honestly just tired people.

  • Use plain words over jargon
  • Write error messages that say how to fix it (“Enter a date like 12/03/2025”) rather than just “Invalid input”
  • Keep link text meaningful on its own (“Download the report” rather than “click here”)

My quick pre-ship checklist

Wrapping up

Accessibility can feel like an endless list of rules. But most of it comes down to a few habits: use the right HTML, never hide focus, label everything, and actually test with a keyboard and a screen reader.

Build those habits and accessible interfaces stop being a separate task. They’re just how you build. And every one of these fixes makes the product a little better for everyone, not just the people we were thinking about when we made it.