The accessibility tree
There's a second tree the browser builds, just for assistive tech. Let's look at it.
When a browser loads your page, it builds the DOM — the document object model, the tree of elements you already know. But it also quietly builds a second tree, just for assistive technology, called the accessibility tree (or a11y tree for short). Screen readers, voice-control software, and braille displays read from this second tree. They never look at your raw HTML directly.
Understanding this is the single biggest mental shift in web accessibility. The DOM is for layout and JavaScript. The a11y tree is for assistive tech. Most accessibility bugs come from forgetting the second tree exists.
What the a11y tree is
The accessibility tree is a simplified version of the DOM that throws away decorative things and keeps the meaningful ones. Each node has a small set of properties:
- Role — what kind of thing it is (button, link, heading, list, image…).
- Name — its label, what gets announced ("Submit", "Search", "Close dialog").
- State — checked, expanded, disabled, pressed, busy, and friends.
- Properties — extras like description, value, position in a set ("3 of 5").
Think of the DOM as the full apartment with all the furniture and dust, and the a11y tree as the floor plan. Same building, different abstraction, very different purpose.
DOM vs accessibility tree
These two trees share the same source HTML but differ in what they keep:
- The DOM keeps every element — every
<div>for spacing, every<span>for color. - The a11y tree drops anything that's purely visual and rolls it into its parent. A
<div>with no role and no special attributes basically disappears into the tree as a generic group.
That's why "div soup" — pages built entirely from <div> and <span> — is a wasteland for screen readers. The DOM is full and busy; the a11y tree is almost empty.
A useful question to ask while building: "If I deleted all the visual styles, would the a11y tree still tell a coherent story about this page?" If not, your structure is leaning on color and layout to mean things — and assistive tech can't see those.
<div class="card"><div class="title">Pricing</div><div>From $9</div></div>. Roughly what does the a11y tree show?Anatomy of an accessible node
Take the simplest element and look at what shows up in its a11y node:
<button type="submit" disabled>Save changes</button>
The accessibility node for that button looks like:
- role: button
- name: "Save changes"
- state: disabled = true
Three properties. Set automatically. Zero ARIA needed. The browser does this work because we used the right element. This is the punchline of accessibility: when the role, name, and state are correct, assistive tech just works.
Viewing it in devtools
You don't have to imagine the a11y tree — every modern browser shows it.
- Chrome / Edge: Open DevTools → Elements panel → side panel "Accessibility". Select an element and you'll see its computed role, name, and ARIA properties. There's also "Full-page accessibility tree" you can enable in the experiments.
- Firefox: DevTools → Accessibility panel. It shows the whole tree and even simulates color-vision deficiencies.
- Safari: In Web Inspector → Audit / Accessibility tab.
Open it now on any page. Click around. You'll see roles you didn't write, names being computed from text content, and possibly some "no name" warnings on icon buttons. That last one is a famous bug: a button containing only an SVG icon has no text, so its computed name is empty — and a screen-reader user just hears "button" with nothing else.
An icon-only button with no aria-label shows up as a nameless button. Always either include visible text, an aria-label, or a visually hidden label.
<button><svg>...</svg></button> for a "Close" icon. The a11y tree shows role=button but the name is empty. What's the simplest correct fix?Sometimes you want something out of the a11y tree — purely decorative icons, an off-screen helper, a duplicated visual. Here's the menu, ordered by reach:
display: noneandvisibility: hidden— hidden from both the visual page and the a11y tree. The element simply doesn't exist for assistive tech.aria-hidden="true"— the element renders visually but is removed from the a11y tree. Use it for decorative icons next to real text labels.role="presentation"(orrole="none") — keeps the element but strips its role. Sometimes used on tables that are purely for layout (don't do this — use CSS for layout).- A class commonly called
.visually-hidden(off-screen but readable) — visible to screen readers, hidden from the visual page. Used for labels that look redundant on screen but help non-visual users.
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}That little snippet shows up in nearly every accessible codebase. It's the opposite of aria-hidden: invisible on the screen, present in the a11y tree.
<button><svg aria-hidden="true">...</svg> Save</button>. What's the accessible name?You now have the mental model: there's a quiet second tree the browser builds, your code shapes it, and assistive tech reads it. In the next lesson we'll meet the rulebook everyone agrees this tree should follow — WCAG.