Skip to content
easeweb

What a screen reader gets from your HTML and ARIA

How the browser turns HTML and ARIA into the accessibility tree a screen reader reads, and where each role, name, description and state in it comes from.

In short: The browser builds an accessibility tree from the DOM: an object for each part of the page, with a role, a name, a description, states and relations, handed to the operating system's accessibility API, where the screen reader reads it. HTML fills the tree on its own; ARIA can change what goes into it, but never what the page does.

01

When you need this

A tester's notes on a recreated settings page come back with three lines:

  • The bin icon is read as "button", and nothing more.
  • "Email alerts" is read as plain text. Nothing says it can be switched, or whether it is on.
  • The hint "Shown on your profile" under the Display name field is never read.

On screen all three look right, and the code holds every word the tester missed. A screen reader doesn't read the code. It reads what the browser hands it, and that is what this page is about.

02

From the DOM to the screen reader

What the person hears passes through four layers:

  1. The DOM: the elements and attributes your HTML and script produce.
  2. The accessibility tree: "User agents acquire information from the DOM and create a parallel structure called the accessibility tree, made up of accessible objects" (AccName 1.1 §1).
  3. The platform accessibility API: the browser exposes each object through the operating system's accessibility API, and fires an event when one changes.
  4. The assistive technology: a screen reader, voice control or a magnifier asks the API what is there and what changed, and turns it into speech, braille or a command.

Core Accessibility API Mappings (Core-AAM) 1.2 §1.1 lists the APIs browsers map to:

Platform Accessibility API
Windows MSAA with IAccessible2, and UI Automation
macOS macOS Accessibility Protocol (AX API)
Linux ATK and AT-SPI
Android Android accessibility API

iOS is not in that list. Each object in the tree carries the same kinds of information, whichever API it reaches:

What Example Where it comes from
Role button, checkbox, link The element, or a role attribute
Name "Delete draft" Content, a label, alt, aria-label or aria-labelledby
Description "Shown on your profile" aria-describedby, or title when it isn't the name
States and properties, the value among them checked, expanded, disabled; a slider's value The element's own state, or aria-* attributes
Relationships labelled by, controls, owns; parent and child label for, aria-labelledby, aria-controls, aria-owns, nesting

Some content never reaches the tree. WAI-ARIA 1.2 counts an element as hidden when it, or an ancestor, is not rendered (display: none) or has aria-hidden="true", and AccName 1.2 lists visibility: hidden as hidden too. Text at opacity: 0, or moved off screen, is not hidden: browsers still expose it. So a badge inside an aria-hidden link leaves the tree with the link, as visible text that screen readers skip shows, while links moved off screen and hidden with aria-hidden still take focus, as aria-hidden content that keyboard focus still reaches shows.

03

Roles: what HTML gives, and what ARIA changes

Every HTML element has an implicit role, the one it maps to with no role attribute. HTML Accessibility API Mappings (HTML-AAM) §3.5 sets them out:

Element Implicit role
<button> button
<a href="…"> link
<a> with no href generic
<input type="checkbox"> checkbox, with its checked state
<nav> navigation
<section> region when it has an accessible name, generic otherwise
<div>, <span> generic

A role attribute replaces the implicit role: ARIA lets an element "be understood as a particular widget or structural type regardless of any semantics inherited from the implementing host language" (WAI-ARIA 1.2 §1.1). WAI-ARIA 1.2 §5.3 sorts its roles into six categories:

Category Roles, for example What it means for authors
Abstract command, composite, input, landmark, range, roletype, section, sectionhead, select, structure, widget, window "Authors MUST NOT use abstract roles in content." They exist to build the model
Widget button, checkbox, option, slider, switch, tab, textbox; and the composites combobox, grid, listbox, menu, radiogroup, tablist, tree Interactive: the page provides the keys and the behaviour
Document structure article, generic, heading, img, list, none, table, toolbar, tooltip Organises content; not usually interactive
Landmark banner, complementary, contentinfo, form, main, navigation, region, search Regions people move between
Live region alert, log, marquee, status, timer Content whose changes are announced
Window alertdialog, dialog A window inside the page

The aria-* attributes are states and properties. WAI-ARIA 1.2 §6.1 says properties such as aria-labelledby are "often less likely to change" than states such as aria-checked, which "may change frequently due to user interaction", and adds that this "is not a rule; a few properties, such as aria-valuetext are expected to change often". The specification mostly calls both "attributes".

None of this changes what the element does. "Aside from using WAI-ARIA markup to improve what is exposed to accessibility APIs, user agents behave as they would natively" (WAI-ARIA 1.2 §1.3). Take this:

<div role="button">Save changes</div>

The tree now holds a button named "Save changes". The div still takes no focus, and Enter and Space still do nothing, because focus and keys come from the element, tabindex and your script, never from ARIA. Div buttons that can't be reached with Tab shows the rest of that story.

04

The rules of ARIA use

The W3C document Using ARIA set out rules for using ARIA in HTML. Its last Working Draft, of 27 September 2018, had five. On 24 February 2026 W3C published it as a Discontinued Draft, which keeps four rules "for historical purposes and for easier reference" and points to the ARIA Authoring Practices Guide for further guidance. It is informative only: advice, not a requirement.

Rule What it says Where it shows
1 Use a native HTML element or attribute with the semantics and behaviour you need, instead of adding ARIA to another element Div buttons that can't be reached with Tab
2 Don't change native semantics unless you really have to: <div role="tab"><h2>…</h2></div>, not <h2 role="tab"> Using ARIA's own example; WAI-ARIA 1.2 gives a tab presentational children (§5.2.9), so browsers should not expose the h2 as a heading
3 All interactive ARIA controls must be usable with the keyboard Arrow keys inside a widget: roving tabindex or aria-activedescendant
4 Don't use role="presentation" or aria-hidden="true" on a focusable element aria-hidden content that keyboard focus still reaches
5 (2018 draft only) All interactive elements must have an accessible name Icon-only buttons with no accessible name

The fifth rule is not in the discontinued version, but the need it described has not gone: WCAG 2.2 success criterion 4.1.2 requires a name for every user interface component.

05

Where the name and the description come from

The browser works out the accessible name with the Accessible Name and Description Computation (AccName). Version 1.1, of 18 December 2018, is the W3C Recommendation; version 1.2 is a Working Draft, dated 21 October 2026 at this page's date. Both take the first source that gives a name, in this order (AccName 1.1 §4.3; the step for a control embedded in a label is left out here):

  1. Hidden: a hidden element gives no name, unless aria-labelledby, aria-describedby or a label points at it.
  2. aria-labelledby: the text of each element it points to, in order. An id that isn't on the page is skipped, as invalid ARIA that misleads screen readers shows.
  3. aria-label: its value. It replaces the text inside the element as the name, which is how a button can show "Add to bag" and be named something else, as in buttons and links named differently from their text.
  4. The element's own label: a label element, alt, a table's caption.
  5. Content: for roles that take their name from content, among them button, link, checkbox, option and tab, the text inside, child by child, with CSS ::before and ::after text. A button holding only an SVG with no title has none, as in icon-only buttons with no accessible name.
  6. Tooltip: title, only when nothing above gave a name.

HTML-AAM §4.1 gives each element its own order within those steps. For a text field: aria-labelledby or aria-label, then its label, then title, then placeholder. For a button: aria-labelledby or aria-label, then a label, then its content, then title. For an img: aria-labelledby or aria-label, then alt, then title.

Some roles can't be named at all. WAI-ARIA 1.2 §5.2.8.6 lists them, generic and paragraph among them, and AccName 1.2 says authors "MUST NOT use the aria-label or aria-labelledby attributes" on them. That is why an aria-label on a plain span may never reach the screen reader, as aria-label on divs and spans that screen readers often skip shows.

The accessible description is a separate property. AccName 1.1 §4.2 builds it from the elements aria-describedby points to. AccName 1.2 and HTML-AAM §4.2, both drafts, add a fuller order: aria-describedby, then aria-description, then features such as a table's caption when it isn't already the name, then title when it isn't already the name. aria-description is not in WAI-ARIA 1.2. When each screen reader reads a description is a question of support, not of the tree: see screen reader support. Names and descriptions compared sets the naming attributes side by side.

06

Reading the tree in developer tools

Both browsers below show the accessibility tree they build from the page. Firefox's inspector shows its own tree, the same on every platform, not the platform API's view of it.

  • Chrome: in the Elements panel, select an element and open the Accessibility tab (it may be behind the More Tabs button). It shows the element's place in the accessibility tree, its ARIA Attributes and its Computed Properties. Turn on "Show accessibility tree" to replace the DOM tree with the full-page accessibility tree.
  • Firefox: open the Accessibility tab in the developer tools, or right-click the page and choose Inspect Accessibility Properties. The left panel lists each object's role and name; the right panel shows its name, role, actions, value, description, states and relations, among others. Check for issues filters the tree to Contrast, Keyboard or Text Labels problems, and Show Tabbing Order numbers the focusable items.

Browsers word roles their own way: Firefox lists a button as "pushbutton". For each control, read the role, the name, the description and the states, and check each against what the screen shows. The tree says whether the information is there. It doesn't say what a screen reader does with it, which depends on the screen reader, its mode and its version; free accessibility tools lists more ways to look.

07

Worked example

The settings page from the tester's notes, as built:

<div class="toggle on" onclick="toggleAlerts()">Email alerts</div>

<button class="icon-button" onclick="deleteDraft()">
  <svg class="icon">
    <use href="#bin"></use>
  </svg>
</button>

<input id="display-name" placeholder="Display name">
<p class="hint">Shown on your profile</p>

Reading each control in the developer tools, then fixing it:

Control In the tree, as built In the tree, after the fix
Email alerts A generic div, whose role can't be named; the words are plain text; no state, and no focus A checkbox named "Email alerts", checked
Bin icon A button with no name: the SVG has no title, so the content gives nothing A button named "Delete draft"
Display name A text field named "Display name", from the placeholder; no description A text field named "Display name", from its label, described as "Shown on your profile"

The fixed markup:

<input type="checkbox" id="alerts" checked>
<label for="alerts">Email alerts</label>

<button type="button" aria-label="Delete draft" onclick="deleteDraft()">
  <svg class="icon" aria-hidden="true">
    <use href="#bin"></use>
  </svg>
</button>

<label for="display-name">Display name</label>
<input id="display-name" aria-describedby="display-name-hint">
<p id="display-name-hint">Shown on your profile</p>

The switch became a native checkbox, so its role, its state and its keys all come from the browser (rule 1). The bin button got a name, and its icon left the tree. The field got a visible label, which is now its name, so the name no longer rests on a placeholder that leaves the screen once someone types; its hint became its description. Reading the tree again, each control now has the role, name, state and description the tester expected. A screen reader test then confirms how each one is heard.

08

Common mistakes

09

What the standard says

  • WCAG 2.2, success criterion 4.1.2 Name, Role, Value (Level A), required: "For all user interface components (including but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies." EN 301 549 V3.2.1 has the same requirement as clause 9.4.1.2; JIS X 8341-3:2016, which is WCAG 2.0, has it as 4.1.2; and Section 508 (E205.4) requires WCAG 2.0 Level A and AA, which includes it.
  • WAI-ARIA 1.2 (W3C Recommendation, 6 June 2023), required of content that uses ARIA: "Authors MUST NOT use abstract roles in content" (§5.3.1). On aria-hidden: "Authors using aria-hidden to hide visible content from screen readers MUST ensure that identical or equivalent meaning and functionality is exposed to assistive technologies." §1.3 and §6.1 explain the model rather than require anything.
  • AccName 1.1 (W3C Recommendation, 18 December 2018), required of browsers: they "MUST compute an accessible name" with its algorithm (§4.1). AccName 1.2 is a Working Draft, and the W3C's publication history shows whether a newer version has been published.
  • HTML-AAM 1.0 (Working Draft, 26 October 2026) and Core-AAM 1.2 (Candidate Recommendation Draft, 30 October 2026): what browsers map, not what authors write. Core-AAM 1.1 is the latest Core-AAM Recommendation.
  • Using ARIA (Discontinued Draft, 24 February 2026): advice only, and no longer maintained.

10

Limits

This page covers what reaches the tree. It doesn't settle:

Whether a control's name or description is the right one for its users is the tester's call, made on the page itself.

11

Terms

accessibility tree
The tree of accessible objects a browser builds from the DOM for assistive technology, each with a role, a name, states and relations.
accessibility API
The interface an operating system gives assistive technology for reading and operating the parts of an application, such as UI Automation on Windows.
accessible name
The short text that identifies an object in the accessibility tree, such as a button's label.
accessible description
Extra text about an object, kept apart from its name, such as the hint under a field.
implicit role
The role an HTML element has with no role attribute, as HTML-AAM maps it: a button element is a button, a nav element is navigation.
abstract role
A role WAI-ARIA uses only to build its model of roles, such as widget or input; authors must not use one in content.

12

Sources and guides

Guides that show it

This page explains a practice, with recreated examples. It is not a screen reader test result, and it is not a finding about a named client.