Inspecting the Accessibility Tree in Chrome DevTools

Permalink to "Inspecting the Accessibility Tree in Chrome DevTools"

When a screen reader announces a grid cell wrongly — “blank”, the wrong header, “clickable” with no name — the cause is almost always visible in the accessibility tree: the structure the browser builds from the DOM and exposes to assistive technology. Chrome DevTools shows that tree, the computed role and name of every node, the source of each name, and which nodes are ignored and why. Learning to read it turns screen reader bug reports from guesswork into a few minutes of inspection.

This guide belongs to accessibility tree & API inspection.

Spec reference

Permalink to "Spec reference"
  • Accessible Name and Description Computation (accname) — the algorithm browsers use to compute names: aria-labelledby, then aria-label, then native labelling (label, caption, alt), then content for roles that allow it, then title.
  • Core Accessibility API Mappings (core-aam) and HTML-AAM — how roles and states map to platform APIs.
  • SC 4.1.2 Name, Role, Value (A) and SC 1.3.1 Info and Relationships (A) — what the tree must express.

The accessibility tree is not identical to what a screen reader says; readers apply their own logic (verbosity, table navigation). But if the tree is wrong, the announcement will be wrong too.

A grid cell in the accessibility tree Hierarchy of computed accessibility nodes: a grid named Invoices, a row with index 3, a column header Amount, and a gridcell whose name comes from its content and which is selected. A grid cell in the accessibility treegrid "Invoices"multiselectable; rowcount 241rowrowindex 3; selected falserowheader "INV-1042"name from contentgridcell "1,240.00"name from content; colindex 4StaticText "1,240.00"leafgridcell ""ignored: aria-hidden on icon, no text — a problem
Each node shows its computed role, name and key properties.

When to use — and when not to

Permalink to "When to use — and when not to"

Inspect the tree whenever an announcement surprises you, before changing any ARIA. Check names, roles and states; check whether nodes are ignored; check relationships (aria-labelledby, aria-describedby, aria-owns, aria-controls).

Do not treat the tree as a substitute for screen reader testing. It shows what the browser exposes; it does not show screen reader quirks like JAWS’s table-reading heuristics or VoiceOver’s grouping. The misapplication: “fixing” a grid by adding aria-labels until DevTools shows the right names, without checking that the visible text and the accessible names still match (SC 2.5.3).

Guessing from markup versus reading the tree Comparison: reading markup leaves you guessing how names and roles are computed; the accessibility tree shows the computed result and its source directly. Guessing from markup versus reading the tree✗ Reading the markup"It has aria-label, so the name is X""role=gridcell should be fine"Hidden elements assumed hiddenRelationships assumed correctState guessed from classes✓ Reading the accessibility treeComputed name and which attribute wonComputed role after implicit and explicitrolesIgnored nodes and the reasonResolved labelledby and describedby targetsaria-selected, aria-expanded, aria-sort ascomputed

Annotated code example

Permalink to "Annotated code example"

A common bug: an icon-only button in a cell with a name that never appears.

<td>
  <!-- Bug: aria-hidden on the button hides it entirely from the tree -->
  <button class="row-menu" aria-hidden="true"><svg viewBox="0 0 20 20">…</svg></button>
</td>

In DevTools: select the button → Accessibility pane → “Ignored: aria-hidden is true”. Fix:

<td>
  <!-- Name from aria-label; icon hidden instead of the button (SC 4.1.2) -->
  <button class="row-menu" aria-label="Actions for INV-1042" aria-haspopup="menu">
    <svg viewBox="0 0 20 20" aria-hidden="true" focusable="false">…</svg>
  </button>
</td>
// Console helper: list computed names of all cells in a row (uses the DevTools-only $0 and getAccessibleName via CDP in automation)
// In automation, Playwright's accessibility snapshot or CDP Accessibility.getPartialAXTree gives the same data:
const { nodes } = await cdp.send('Accessibility.getPartialAXTree', { backendNodeId, fetchRelatives: false });
console.log(nodes.map(n => [n.role?.value, n.name?.value, n.ignored]));

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"

Use the tree alongside a screen reader: when an announcement is wrong, inspect the node the reader is on.

Announcement problem What to look at in the tree Typical cause
“blank” on a cell Cell name empty Content in an aria-hidden child or CSS content
Wrong column header Header cell role and position th missing scope, or header outside the table
“clickable” with no name Button or generic with click listener Div with onclick, no role or name
Expanded state not announced aria-expanded on the right node State on a child instead of the row
Sort not announced aria-sort on columnheader aria-sort on the button inside the header
Debugging an announcement in five steps Flow: reproduce with a screen reader; select the node in DevTools; read role, name and properties; check the name source and ignored status; change markup and re-check the tree before re-testing with the reader. Debugging an announcement in five stepsReproducescreen reader says "blank"note the cellSelect nodeElements panel, then Accessibility paneor full-page treeRead computed valuesrole, name, statescompare with expectationCheck sourcesname computation; ignored reasonfind the causeFix and verifyre-check tree, then screen readerboth must agree

Integration context

Permalink to "Integration context"

Firefox offers a complementary view — see the Firefox accessibility inspector for data grids. To turn tree inspection into automated tests, see ARIA snapshot testing with Playwright. Tree size matters for performance; measuring it is covered in measuring accessibility tree cost.

Gotchas

Permalink to "Gotchas"

Lazy tree building. Chrome builds parts of the tree lazily; enable “full-page accessibility tree” and refresh if nodes seem missing.

Shadow DOM. Nodes inside shadow roots appear in the tree, but aria-labelledby cannot cross shadow boundaries; the tree will show an empty name.

Live regions. The tree shows live properties but not whether an announcement fired. Use a screen reader or speech log to verify announcements.

Common mistakes

Permalink to "Common mistakes"
  • Debugging by reading markup only.
  • Fixing names with aria-label that no longer match visible text.
  • Forgetting to check ignored nodes.
  • Assuming the tree equals the screen reader’s output.

Framework notes

Permalink to "Framework notes"

React, Vue and Angular DevTools show components, not accessibility; use them to find the component, then the browser’s accessibility pane to see the result. Component libraries sometimes render extra wrapper elements with roles; the tree reveals them (for example, a presentation table inside a grid). When a library’s announcement is wrong, the tree tells you whether the library or your configuration is at fault.

Worked example

Permalink to "Worked example"

A team received a report: “NVDA says ‘blank’ on every Status cell.” Inspecting a Status cell in Chrome’s accessibility pane showed an empty name; the full-page tree showed the badge text inside a span with aria-hidden="true", added to stop a tooltip duplicate. The real fix was to remove aria-hidden from the badge and remove the duplicate tooltip text instead. Fifteen minutes of inspection replaced what had been a week of speculative ARIA changes.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Add “accessibility tree snapshot” screenshots to component documentation showing the expected roles and names for each state. Reviewers can then compare a product’s tree to the reference.

FAQ

Permalink to "FAQ"
Is the accessibility tree the same in every browser?

The structure is similar, but mappings differ. Check Chrome and Firefox when behaviour differs between readers.

Can I edit ARIA in DevTools and see the result?

Yes — edit attributes in the Elements panel and re-select the node; the Accessibility pane updates.

Why is a node "ignored"?

Common reasons: aria-hidden, display: none, role=“presentation” on an element with no interactive content, or being empty.

Does the tree show what a screen reader will say?

Not exactly. It shows the information screen readers use. Readers add their own wording and logic.

How do I see the accessibility tree of a whole page?

Enable the full-page tree toggle in the Elements panel; it replaces the DOM tree view with the accessibility tree.

What about Safari?

Safari’s Web Inspector has an accessibility section showing role, label and properties; useful for VoiceOver-specific issues.

Permalink to "Related"

← Back to Accessibility Tree & API Inspection