HTML · Production

Accessibility

Accessibility (often written a11y) means everyone can use your site — including people who are blind, use only a keyboard, or have low vision. Good HTML gets you 80% of the way for free.

Advanced 6 min Lesson 19 of 22 Runnable examplesFollows the WHATWG HTML Living Standard.
Before you start:Semantic HTMLForms
0/22 in HTML
On this page · 6 min · Advanced

Learning objectives#

  • Explain who accessibility helps
  • Use native elements that are keyboard-accessible by default
  • Label forms, images and icons properly
  • Use ARIA only when HTML is not enough
  • Test a page with the keyboard and a screen reader

Explanation#

Around one in six people has a disability. Some use screen readers that read the page aloud, some use only a keyboard, some zoom to 200% or more.

Native elements come with accessibility built in: a <button> can be focused with Tab, pressed with Enter or Space, and is announced as “button”. A <div onclick> has none of that.

Everything needs a name a screen reader can say: <label> for inputs, alt for images, text or aria-label for icon-only buttons.

ARIA attributes (aria-label, aria-expanded, role) add meaning when HTML has no suitable element. The first rule of ARIA: if a native element exists, use it instead.

Never remove the focus outline without replacing it — keyboard users need to see where they are.

Code example: Accessible vs inaccessible#

HTMLAccessible vs inaccessible Runnable
<style>
  .bad  { color:#bbb; cursor:pointer; }
  button:focus-visible { outline: 3px solid #2965f1; outline-offset: 2px; }
</style>


<!-- ✗ Not focusable, not announced, low contrast -->
<div class="bad" onclick="alert('Saved')">Save</div>


<!-- ✓ Keyboard + screen reader friendly -->
<button type="button" onclick="alert('Saved')">Save</button>


<!-- ✓ Icon-only button with an accessible name -->
<button type="button" aria-label="Close menu">✕</button>


<!-- ✓ Toggle that announces its state -->
<button type="button" aria-expanded="false" aria-controls="menu"
  onclick="const o=this.getAttribute('aria-expanded')==='true';this.setAttribute('aria-expanded',!o);menu.hidden=o">
  Menu
</button>
<ul id="menu" hidden><li><a href="#">Home</a></li></ul>


<!-- ✓ A skip link lets keyboard users jump past the menu -->
<a href="#main">Skip to main content</a>
Expected output
Try pressing Tab: the grey “Save” div is skipped, but every real button receives a visible blue focus ring.
Opens this example in the full playground

Step-by-step explanation#

  1. The div looks clickable but cannot be reached with Tab and is announced as plain text.
  2. The <button> works with mouse, keyboard and screen readers automatically.
  3. aria-label gives the ✕ icon a spoken name: “Close menu, button”.
  4. aria-expanded tells screen readers whether the menu is open or closed.
  5. :focus-visible draws a clear outline for keyboard users only.
  6. A “skip link” at the top of real pages lets keyboard users jump straight to <main id="main">.

Real-world use case#

Government, banking and education sites are legally required to be accessible in many countries (WCAG 2.2 AA). Accessible sites also work better for everyone — on phones, in sunlight, with a broken mouse.

Common mistakes#

outline: none on focus

This makes the page unusable for keyboard users. Style :focus-visible instead of removing it.

Colour as the only signal

“Fields in red are required” fails for colour-blind users. Add text or an icon too.

Adding ARIA to fix the wrong element

<div role="button" tabindex="0"> still needs keyboard handling you must write yourself. A <button> is simpler and correct.

Best practices#

  • Use native HTML elements first
  • Every input has a label, every image has alt, every icon button has a name
  • Keep text contrast at least 4.5:1
  • Test by unplugging your mouse and using only Tab, Enter, Space and arrow keys
  • Try a screen reader: NVDA (Windows) or VoiceOver (Mac / iPhone)

Remember this#

If you can’t Tab to it, a keyboard user can’t use it.

First rule of ARIA: don’t use ARIA (if HTML can do it).

Every control needs a name a screen reader can say out loud.

Practice exercise#

Your task: Make this accessible: <div onclick="search()"><img src="search.svg"></div>

Need a hint?
Use a button, and give it a name. The icon itself becomes decorative.
Show solution
HTML Illustrative
<button type="button" onclick="search()" aria-label="Search">
  <img src="search.svg" alt="">
</button>

Mini quiz#

Accessibility quizMultiple choice Question 1 of 3

What is the best element for a clickable “Save” action?

Score so far: 0/0

Want more? Practise all HTML MCQs · HTML interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.