HTML Accessibility (a11y)

Build pages everyone can use, including screen-reader and keyboard users.

Lesson 38 of 44Intermediate14 min read

Accessibility (often shortened to a11y, because there are 11 letters between the "a" and the "y") means building websites that everyone can use. That includes people who are blind and use screen readers, people who can't use a mouse, people with low vision or colour blindness, and anyone with a broken arm or bright sunlight on their screen.

The good news is that most accessibility comes from writing good, semantic HTML. If you've followed the earlier lessons, you already know much of it. This lesson pulls those habits together and adds a few more, so you can check any page you build.

How people browse the web differently

  • Screen readers such as VoiceOver, NVDA and JAWS read the page aloud and let people jump between headings, links, landmarks and form fields.
  • Keyboard users press Tab to move between links and buttons, and Enter or Space to use them.
  • Zoom users magnify text to 200% or more, so layouts must still work at large sizes.
  • Colour-blind users can't rely on a difference between red and green alone.

A quick way to experience this: put your mouse away and try to use one of your own pages with only the keyboard.

Six habits that make HTML accessible

  1. Use the right element. Real <button>, <a>, <nav> and <main> elements come with keyboard and screen-reader support built in.
  2. Add alt text to images. Describe meaningful images, and use alt="" for decoration.
  3. Label every form field, connecting the label with for and id.
  4. Keep a logical heading outline: one <h1>, then <h2> and <h3> in order.
  5. Write descriptive link text instead of "click here".
  6. Set the page language with <html lang="en">.

Keyboard focus and colour contrast

When someone tabs through a page, the browser draws an outline around the focused element. That outline is how keyboard users know where they are, so never remove it without providing a clear replacement style.

Text also needs enough contrast against its background. Light grey text on a white background may look elegant, but many people can't read it. The WCAG guidelines recommend a contrast ratio of at least 4.5 to 1 for normal text, and browser developer tools can check this for you.

ARIA attributes: the last resort

ARIA attributes add extra information for assistive technology:

  • aria-label="Close" gives a name to a button that only shows an icon.
  • aria-expanded="true" tells users a menu is open.
  • aria-live="polite" announces content that changes, such as "Item added to basket".
  • aria-hidden="true" hides decorative things, such as icons, from screen readers.

The first rule of ARIA is: if a native HTML element does the job, use that instead. A <button> beats <div role="button"> every time, because the native element already handles focus, keyboard presses and announcements.

HTML Accessibility Syntax

Common accessible patterns

<img src="chart.png" alt="Sales rose 40% in 2026">
<label for="q">Search</label> <input id="q" type="search">
<button type="button" aria-label="Close menu">✕</button>
<a class="skip-link" href="#main">Skip to content</a>

HTML Accessibility Summary

  • Accessibility means people can use your site regardless of disability or device.
  • Semantic HTML provides most accessibility features automatically.
  • Use alt text, form labels, a clear heading outline and descriptive links.
  • Keep the focus outline visible and use strong colour contrast.
  • Reach for ARIA only when no native HTML element does the job.

HTML Accessibility Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

An icon button with a name

The ✕ means nothing to a screen reader. aria-label gives the button a name. Press Tab in the result to see the keyboard focus ring.

<div role="alertdialog" aria-labelledby="t">
  <h3 id="t">Cookies</h3>
  <p>We only use cookies to remember your theme.</p>
  <button type="button">Accept</button>
  <button type="button" aria-label="Close notice">✕</button>
</div>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1aria-labelledby points to the heading, so the dialog is announced as "Cookies".
  2. Line 4A normal button. Its text is its name.
  3. Line 5An icon-only button. aria-label is what a screen reader says.
Example 2

Live announcements

Click the button. Screen readers announce the text inside aria-live whenever it changes, without moving the user's focus.

<button type="button" onclick="document.getElementById('cart').textContent = 'Added! 2 items in your basket.'">
  Add to basket
</button>
<p id="cart" aria-live="polite">Your basket is empty.</p>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 1 to 3A real button, so it works with mouse, keyboard and touch.
  2. Line 4aria-live="polite" waits until the screen reader finishes speaking, then announces the new text.
Example 3

A skip link

Press Tab once in the result: a "Skip to content" link appears. Keyboard users can jump past long menus. This site has one too, so try it here.

<a href="#main" class="skip">Skip to content</a>
<nav>Home · Shop · Blog · About · Contact · Help</nav>
<main id="main" tabindex="-1">
  <h1>Welcome</h1>
</main>

<style>
  .skip { position: absolute; left: -999px; }
  .skip:focus { left: 8px; top: 8px; background: #ffd23f; padding: 6px 10px; }
</style>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1The skip link points at #main.
  2. Lines 8 to 9It's hidden off-screen until it receives keyboard focus.

Common HTML Accessibility Mistakes

Clickable divs

Don't
<div class="btn" onclick="save()">Save</div>
Do
<button type="button" class="btn" onclick="save()">Save</button>

The div can't be reached with Tab, doesn't respond to Enter, and isn't announced as a button.

Colour as the only signal

Don't
<p style="color: red">Email</p>
<input type="email">
<!-- red = error? -->
Do
<label for="em">Email</label>
<input id="em" type="email" aria-describedby="em-err">
<p id="em-err">⚠ Please enter a valid email address.</p>

Colour-blind users can't see "red means error". Add text or an icon, and connect the message to the field.

Removing the focus outline

Don't
<style> *:focus { outline: none; } </style>
Do
<style> *:focus-visible { outline: 3px solid #17a865; outline-offset: 2px; } </style>

Keyboard users rely on the outline to know where they are. Style it, but never delete it.

HTML Accessibility in Real Projects

Accessibility helps everyone

Captions help people in noisy cafés. Big buttons help people on bumpy buses. Good contrast helps everyone outdoors. Clear headings help everyone skim. And because search engines read pages a bit like screen readers do, accessible pages often rank better too.

HTML Accessibility Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Give the icon-only search button an accessible name.

<button type="button" ="Search">🔍</button>
Multiple choiceeasy

What's the first rule of ARIA?

Multiple choicemedium

Which key do keyboard users press to move to the next link or button?

Fix the bughard

Make this mini form accessible: connect the label, give the image alt text, and turn the clickable div into a real submit button.

<img src="https://picsum.photos/id/292/120/80" width="120" height="80">
<form>
  <label>Your email</label>
  <input type="email" id="news-email" name="email">
  <div onclick="this.closest('form').requestSubmit()">Subscribe</div>
</form>
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Image has alt text
  • Label is connected to the input
  • There's a real submit button
  • No clickable div left

HTML Accessibility Quiz

4 questions to check what you learned.

  1. What does "a11y" mean?

    • Ally, a JavaScript library
    • An HTML attribute
    • Version 11 of HTML
    • Accessibility (a + 11 letters + y)
  2. Which attribute announces changing content to screen readers?

    • aria-hidden
    • aria-change
    • aria-live
    • role="alert-me"
  3. What is WCAG?

    • A CSS framework
    • The Web Content Accessibility Guidelines
    • A screen reader
    • A Google ranking tool
  4. Why is outline: none on focus a problem?

    • Keyboard users can no longer see which element is focused
    • It slows the page down
    • It breaks links
    • It's invalid CSS

HTML Accessibility Challenge

Fix the hamburger menu button

This menu button uses only an icon. Make it accessible:

  1. Change the <span> into a <button type="button">
  2. Give it aria-label="Open menu"
  3. Add aria-expanded="false"
<span class="menu-btn" onclick="this.textContent = '✕'">☰</span>
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • It's a real button
  • It has aria-label="Open menu"
  • It has aria-expanded="false"
  • No span left