Accessibility & Standards

Semantic HTML

Definition

Every HTML element carries a built-in role, and that role is what assistive technology reports. A button element is announced as a button; a div with a click handler is announced as nothing. The difference is concrete rather than philosophical. A real button is in the tab order without any attribute, fires on both Enter and Space, can be disabled, submits a form, works with voice control when the user says its visible label, and gets a focus ring from the browser. A styled div does none of those things until you add them by hand: tabindex of zero, a role of button, a keydown listener for Enter, a second one for Space with the default prevented so the page does not scroll, and CSS for focus. Semantic elements are also how headings, lists, tables and landmarks reach the accessibility tree, which is how screen reader users navigate.

Why It Matters

This matters more than it used to because generated code produces divs. Ask a model or a design tool for a card with an action on it and you will often get nested div elements with click handlers, which look correct and are unreachable from a keyboard. The repair is five separate pieces of code per control, each of which can be got wrong, against one element that works. Semantics also carry structure: WebAIM's screen reader surveys consistently find that headings are the first thing users reach for when finding content on an unfamiliar page, ahead of landmarks and the find command. A page built from div elements with font sizes instead of h1 to h6 gives them nothing to navigate by, and turns a ten-second scan into a full read.

How It Works

The browser maps each element to a role, a name, a value and a set of states, and exposes that as the accessibility tree next to the DOM. Native elements populate it automatically: h2 arrives as a heading at level 2, ul as a list with a count of items, nav as a navigation landmark, input with an associated label as a textbox with that name, table with th cells as a grid with row and column headers. Keyboard behaviour is baked into the same elements by the browser, which is why a select element gets arrow keys, typeahead and a native picker on mobile for free. Where no element fits — a tab set, a tree, a combobox — ARIA roles and states fill the gap, and then the keyboard behaviour really is yours to write.

Real-World Example

Someone exports a prompted expenses tool to a single HTML file and publishes it at expenses.99helpers.site. The 'Add row' control is a div with a click handler and a hover style, and the 'Remove' controls are spans. A mouse user notices nothing; a keyboard user cannot reach either control, because neither element is focusable. Swapping both for button elements with type of button removes nine lines of event code, adds keyboard support, restores the focus ring, and makes the controls announce as buttons. The file is re-uploaded to the same 99helpers address and the previous version stays in the version history.

Common Mistakes

  • Using a div with a click handler as a button — it is not focusable, does not respond to Enter or Space, and is announced with no role at all
  • Choosing heading levels by how big the text looks — heading levels are structure, and size belongs in CSS, so an h3 styled large beats an h1 used for emphasis
  • Patching a generic element with role of button instead of using a button — the role fixes the announcement only, leaving focus and key handling entirely to you

Related Terms

Put a file online in seconds

Drop in a document, an image, a page or a whole static website and share the link — free, with no build step and no server to set up.

Host a file free →