The Accessibility Tree: What Your DOM Doesn’t Tell You About Screen Readers
Why your perfectly structured HTML might still confuse assistive technologies—and how to peek behind the curtain
July 11, 2026

Ever been confident your HTML is perfectly semantic, using <button>, <nav>, and all the right ARIA roles, only to have an accessibility audit or screen reader feedback tell you something's missing or just plain wrong? I know the feeling. You open your app in VoiceOver or NVDA, and suddenly the UI reads out weird or skips over important parts.
Turns out, what you see in the DOM isn’t exactly what assistive technologies experience. They rely on something called the accessibility tree, a hidden cousin of your DOM that browsers build behind the scenes. It’s like debugging the ghost in your UI machine.
What is the Accessibility Tree?
Think of your DOM as the source code for the page’s structure. The accessibility tree is the version of that structure the browser crafts specifically for screen readers and other assistive tech. It’s a filtered, enhanced, and sometimes entirely different representation.
Every element in your DOM doesn’t automatically make it into the accessibility tree. Some elements are ignored, others are merged, and some properties get adjusted based on CSS, ARIA attributes, and even browser heuristics.
For example, a <div> with role="button" appears as a button in the accessibility tree, but a visually hidden element with display: none or visibility: hidden is usually left out completely.
How the Accessibility Tree Gets Built
The process starts with the DOM. The browser traverses your markup, collects nodes that could be accessible, and applies a bunch of rules:
-
Role calculation: Native HTML elements have implicit roles (
<button>is "button",<ul>is "list"). ARIA roles can override or supplement these. -
Name and description computation: The browser tries to figure out what to call the element. It looks at aria-label, aria-labelledby, alt attributes, and sometimes visible text.
-
State and properties: Things like
aria-checked,aria-expanded, or even CSSvisibilityanddisplayaffect whether and how elements appear. -
Child flattening: Some elements are hidden or ignored, but their children might be "flattened" into a parent, meaning the accessibility tree can differ wildly from the DOM tree shape.
-
Focusability and keyboard navigation: Elements that can receive focus or keyboard events get special treatment.
The result is a tree with nodes called accessible objects or AXNodes that assistive tech consumes. It's not a 1:1 mapping.
Why CSS Matters More Than You Think
You might think CSS is just about visuals, but it actually shapes the accessibility tree too.
For instance, display: none and visibility: hidden remove elements from the accessibility tree entirely. But opacity: 0 or transform: scale(0) keep elements visible to screen readers even though they’re invisible to sighted users.
Ever wonder why some hidden modals still get read by screen readers? Sometimes devs use opacity: 0 or move the element off-screen with transforms instead of display: none. Screen readers don’t care about those visual tricks, they see the element as present.
That’s why managing the accessibility tree means managing CSS too.
Peek Under the Hood: Inspecting the Accessibility Tree
Modern browser devtools have started exposing accessibility trees, but the tooling is still rough.
In Chrome DevTools:
- Right-click an element and choose Inspect.
- Go to the Accessibility pane on the right.
- You’ll see the computed role, name, and properties the browser assigned.
- There’s also an Accessibility Tree tab where you can explore the AXNode hierarchy.
This is your window into what assistive tech actually sees.
If you find elements missing or roles incorrect, check:
- Are you accidentally hiding things with CSS?
- Is your ARIA markup correct and complete?
- Is the element focusable if it should be?
Common Accessibility Tree Gotchas
1. Invisible but Focusable
You might hide an element visually but keep it keyboard focusable unintentionally. For example, a button with opacity: 0 is invisible but still in the accessibility tree and can confuse keyboard users.
2. Missing Names
Screen readers need a name to announce elements. If you rely on visual text alone but forget aria-label or aria-labelledby for custom controls, the accessibility tree might show an unnamed node.
3. Duplicate or Conflicting Roles
Sometimes roles from ARIA clash with native semantics, or multiple roles get assigned, leading to unpredictable behavior.
4. Flattened Children
Containers like <fieldset> or ARIA groups can flatten their children, changing navigation order.
Debugging Tips
- Use browser accessibility inspectors to compare your DOM and accessibility tree.
- Test with multiple screen readers (NVDA, VoiceOver, JAWS) because they sometimes interpret the tree differently.
- Check computed roles and names in devtools.
- Avoid hiding elements with
opacity: 0orvisibility: hiddenif you want them removed from the accessibility tree; usedisplay: noneor thehiddenattribute instead. - Validate ARIA roles and properties with linters and validators.
Wrapping Up
Your DOM is just the starting point. The accessibility tree is where the real magic, or confusion, happens for assistive tech.
Next time a screen reader user reports weird behavior, don’t just check your HTML. Peek into the accessibility tree. You might find hidden elements, missing names, or unexpected roles lurking in there.
Understanding this invisible structure helps you build UI that’s truly accessible, no surprises, no guesswork.
And hey, the more you know about what the browser actually exposes, the better your next debugging session will go.