Frontend
Lesson 2 of 8About 3 min readSuggest an edit

Accessible HTML

About one in six people lives with a disability, and everyone is temporarily impaired sometimes: a broken arm, a bright screen, a noisy train. Accessible HTML is mostly not extra work. It is using the elements the browser already understands.

Semantics carry meaning

Screen readers, voice control and keyboard navigation all rely on the accessibility tree, which the browser builds from your HTML. A <button> arrives in that tree as a button: focusable, announced as “button”, activated by Enter and Space. A <div> with a click handler arrives as nothing.

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

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

Use landmarks so people can jump around the page: <header>, <nav>, <main>, <footer>. Use headings <h1> to <h6> in order, because screen reader users often navigate by heading list. Use <a href> for navigation and <button> for actions; mixing them up breaks expectations such as opening a link in a new tab.

Every input needs a label

A placeholder is not a label: it disappears when you type and is often low contrast.

<label for="email">Email</label>
<input id="email" type="email" autocomplete="email" required>

Clicking the label focuses the input, and a screen reader announces “Email, edit text, required”. For groups of radio buttons or checkboxes, wrap them in <fieldset> with a <legend> so the question is read with each option.

Text alternatives

Every meaningful image needs alt text that says what the image communicates, not what it looks like. A chart’s alt text should state its conclusion. Decorative images get an empty alt="" so assistive technology skips them. Icon-only buttons need an accessible name, either visually hidden text or aria-label.

Keyboard access and focus

Everything you can do with a mouse must work with a keyboard. Test by unplugging the mouse: press Tab through the page and check that:

  • every interactive element receives focus, in a logical order;
  • the focused element is clearly visible (never remove the outline without replacing it);
  • nothing traps focus, except a modal dialog while it is open;
  • when content changes, focus moves somewhere sensible. After opening a dialog, focus goes into it; after closing it, focus returns to the button that opened it.

Avoid positive tabindex values; they create a focus order nobody can predict.

ARIA: the first rule

ARIA attributes change what the accessibility tree says about an element. The first rule of ARIA is don’t use ARIA if a native element does the job. role="button" on a <div> promises button behaviour, but you must then add focus, Enter and Space handling yourself.

ARIA shines where HTML has no equivalent:

  • aria-live="polite" announces updates such as “Saved” or search result counts;
  • aria-expanded tells users whether a disclosure is open;
  • aria-describedby links an input to its error message.

Colour and contrast

Body text needs a contrast ratio of at least 4.5:1 against its background (3:1 for large text). Never use colour alone to carry meaning: a red border on an invalid field also needs an error message or icon.

Test it

Automated checkers such as axe catch roughly a third of issues: missing labels, low contrast, invalid ARIA. The rest needs people: a keyboard pass, a screen reader pass (VoiceOver on macOS and iOS, NVDA on Windows, TalkBack on Android) and zooming to 200%.

Next: State and rendering in UI frameworks

How components turn state into UI, what triggers a re-render, and the mistakes that cause bugs.