The invisible DOM
There are two trees. You wrote one of them. Assistive technology reads the other.
- Level
- ENGINEER
- Read time
- 10 min
- Experiment
- Available
- Type
- INTERACTIVE
The question
A div with a click handler looks and behaves like a button on screen. What exactly is missing, and where does that difference live?
Hypothesis
The browser derives an accessibility tree from the DOM. Native elements contribute a role, a name, states and built-in keyboard behaviour; a styled div contributes a generic node with none of those.
Method
Laboratory available
The instrument for this investigation runs in the laboratory, where the controls, the live model and the observation log share one workstation.
Enter the laboratoryEdit the markup on the left. The accessibility tree on the right is recomputed with the role, accessible name and state that assistive technology would actually receive.
What we observed
| Capability | <button> | <div onclick> |
|---|---|---|
| Role announced | button | generic |
| Reachable by Tab | yes | no (needs tabindex="0") |
| Enter and Space activate it | yes | no (needs a keydown handler) |
| Disabled state honoured | yes | no |
| Participates in a form | yes | no |
| Exposed to voice control by name | yes | only with an explicit name |
| Shows in the browser's find-and-click tooling | yes | unreliable |
Why it happens
<!-- Correct: role, focus, keyboard, disabled all included --><button type="button" onclick="save()">Save</button><!-- Recoverable, but you now own the keyboard contract --><div role="button" tabindex="0" onclick="save()" onkeydown="if (event.key === 'Enter' || event.key === ' ') save()">Save</div><!-- Invisible to keyboard and assistive technology --><div class="btn" onclick="save()">Save</div>Visual hiding has three distinct meanings and people routinely pick the wrong one. display: none and visibility: hidden remove the node from the accessibility tree. opacity: 0 and clip-path do not, the content stays announced and focusable, which is how invisible focus traps happen. A visually-hidden utility class is the correct tool for text intended only for screen readers.
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;}Further research
The accessibility tree is not a copy of the DOM. Presentational nodes are pruned, anonymous boxes are ignored, and generated content may or may not appear. Browsers expose it through platform APIs. UIA on Windows, AX on macOS, AT-SPI on Linux, so two browsers can legitimately expose the same markup slightly differently. Chrome DevTools, Firefox's Accessibility panel and Safari's Audit tab all let you read the computed tree directly.
References
- 01W3C, accnameAccessible name and description computation
- 02W3CARIA Authoring Practices Guide
- 03MDNThe accessibility tree