Chapter 2: DOM Tree vs Accessibility Tree

What the browser sees vs what assistive tech understands and why that distinction matters


Most front-end developers know about the DOM.
But very few understand the Accessibility Tree, let alone how it’s created, how it works, or how to debug it.

alt text

If you’ve ever used a screen reader and thought, “Why isn’t it reading what I expect?”
Or if you’ve added ARIA roles without really knowing why…

This chapter is for you.


Section 2.1: What Is the DOM Tree?

The DOM (Document Object Model) is the browser’s internal representation of your HTML.
It’s a live, dynamic tree of nodes that JavaScript can read, update, and traverse.

When you write this:

<h1>Hello, world</h1>

The browser parses it into this:

Document
└── html
    └── body
        └── h1 ("Hello, world")

This structure is:

The DOM tree is for the browser. It reflects everything, including elements that are hidden, purely visual, or meaningless to users.


Section 2.2: So What’s the Accessibility Tree?

The Accessibility Tree is a simplified version of the DOM that assistive technologies (like screen readers) use to understand and interact with your page.

Think of it as the semantic version of the DOM.

It’s built by the browser using:

  1. HTML semantics
  2. ARIA attributes
  3. Computed styles (like display: none)
  4. Element focusability

It filters out things that don’t matter to assistive tools and highlights roles, names, states, and relationships.


Why Two Trees?

Because screen readers don’t care about layout.
They care about:

If the DOM is the full script, the Accessibility Tree is the stage directions for users who don’t see the play.


Section 2.3: Building Blocks of the Accessibility Tree

Each node in the Accessibility Tree has:

Property Meaning
Role What it is (e.g. button, heading, link)
Name What it says (e.g. “Submit”, “Search”)
State Its status (e.g. aria-checked="true")
Relations How it links to others (e.g. label → input)
Focus Whether it’s reachable by keyboard

Examples

Native button

<button>Send</button>

Accessible node:


Custom button with div

<div onclick="send()" role="button" tabindex="0">Send</div>

Accessible node:

It works, but it’s fragile. Use native elements whenever possible.


Non-accessible element

<span class="hidden">Warning!</span>

If .hidden { display: none; }, then:


Section 2.4: How the Browser Builds the Tree

Step-by-step:

  1. Parse the DOM from your HTML
  2. Remove hidden elements (display: none, aria-hidden="true")
  3. Infer roles from tags (<button> = role: button)
  4. Compute names from:
    • Text content
    • aria-label
    • Associated <label> elements
  5. Add states from ARIA (aria-expanded, aria-disabled, etc.)
  6. Link relationships via aria-describedby, aria-labelledby

This runs in real-time and updates as your JS modifies the DOM.


Section 2.5: How to Inspect the Accessibility Tree

In Chrome:

  1. Right-click → Inspect
  2. Open the Accessibility tab in DevTools
  3. Select any element
  4. View:
    • Role
    • Name
    • Keyboard-focusable
    • Ignored status

Bonus: Enable full tree with chrome://accessibility


DevTools Example

<button aria-label="Send email">📤</button>

DevTools Accessibility panel shows:

Even though there’s no visible text, the button is named.


Section 2.6: Real Mistakes Developers Make

Placeholder instead of label

<input type="text" placeholder="Email" />

Placeholder disappears on focus. Screen readers don’t treat it like a label.

Do this:

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

Using display: none instead of hiding visually

.visually-hidden {
  display: none;
}

Use:

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  clip: rect(0 0 0 0);
  overflow: hidden;
  white-space: nowrap;
}

This keeps it visible to screen readers but hidden from sighted users.


Not using aria-describedby

<input id="name" />
<p id="name-help">Your full legal name</p>

Add:

<input id="name" aria-describedby="name-help" />

Now screen readers read both input + hint.


Section 2.7: Accessibility APIs Behind the Scenes

The Accessibility Tree is not just DevTools sugar, it’s how the browser communicates with the OS.

It sends this data to:

Which powers:

If your Accessibility Tree is broken, the entire assistive ecosystem is broken for your users.


Final Checklist


Resources to Go Deeper


Coming Up Next

In Chapter 3, we’ll explore how the browser calculates layout: margins, paddings, borders, collapsing behavior, and real-world debugging of rendering issues using Chrome DevTools.

This is where the pixels hit the screen and where you’ll stop fighting the box model.