Accessibility Tree & API Inspection

Permalink to "Accessibility Tree & API Inspection"

Every screen reader announcement starts as markup, becomes a node in the browser’s accessibility tree, is mapped to a platform accessibility API and is finally interpreted by the screen reader. When an announcement is wrong — “blank”, the wrong header, a missing “expanded” — the fault lies at one of those layers. Teams that can only test by listening to a screen reader end up guessing: they add aria-labels, wrap things in role="presentation", change elements, and hope. Teams that can read the accessibility tree find causes in minutes.

This topic covers the inspection tools and the tests that build on them, applied to data grids and the controls around them. The users affected are, ultimately, all assistive technology users, because faster diagnosis means fewer regressions and quicker fixes. The failure this topic prevents is accessibility work driven by trial and error instead of evidence — slow, expensive, and prone to creating new problems while fixing old ones.

This topic belongs to testing & auditing accessible data interfaces.

WCAG criteria in scope

Permalink to "WCAG criteria in scope"
Criterion Level What inspection verifies
1.3.1 Info and Relationships A Roles, headers and relationships in the tree
2.1.1 Keyboard A Focusable elements and tab stops
2.4.3 Focus Order A Tab order overlays
2.5.3 Label in Name A Visible text contained in computed names
4.1.2 Name, Role, Value A Computed names, roles and states
4.1.3 Status Messages AA Live region nodes and their content

Prerequisites

Permalink to "Prerequisites"
Where each tool looks Layers from markup to output with the tools that inspect each: markup (code review, linters), browser accessibility tree (Chrome DevTools, Firefox inspector, ARIA snapshots), platform API (Accessibility Insights for Windows, macOS Accessibility Inspector, Accerciser), and speech output (speech logs, screen readers). Where each tool looksMarkupcode review; linters; axe-core rulesBrowser treeChrome DevTools; Firefox inspector; ARIA snapshotsPlatform APIAccessibility Insights for Windows; macOS Accessibility Inspector; AccerciserSpeech outputscreen readers; NVDA speech logs; Guidepup
Diagnose from the top down; stop at the first wrong layer.

ARIA & HTML spec reference

Permalink to "ARIA & HTML spec reference"
Concept Where to see it Why it matters for grids
Computed role DevTools Accessibility pane grid vs table decides reader mode
Computed name and source DevTools name computation Empty or duplicated cell names
Ignored nodes DevTools, Firefox inspector Content hidden by aria-hidden or presentation
States (selected, expanded, sort) Both inspectors, ARIA snapshots Missing or misplaced states
Relations (labelledby, controls) Firefox inspector Popovers, headers and descriptions
Platform patterns (UIA Table, AX headers) Platform inspectors Reader-specific header issues

Step-by-step implementation

Permalink to "Step-by-step implementation"

Step 1 — Reproduce and select (SC 4.1.2)

Permalink to "Step 1 — Reproduce and select (SC 4.1.2)"

Reproduce the announcement, then select the same node in DevTools. See inspecting the accessibility tree in Chrome DevTools.

Accessibility pane → Computed properties → Name: "" (from content: aria-hidden child)

Step 2 — Compare with the pattern

Permalink to "Step 2 — Compare with the pattern"

Check the node against the pattern’s requirements (role, name, states, position).

Step 3 — Cross-check in Firefox

Permalink to "Step 3 — Cross-check in Firefox"

See the Firefox accessibility inspector for data grids.

Relations → controller for: dialog "Filter Amount"

Step 4 — FastPass per state (SC 2.1.1, 2.4.3)

Permalink to "Step 4 — FastPass per state (SC 2.1.1, 2.4.3)"

See Accessibility Insights FastPass on data pages.

expect(await page.evaluate(() => [...document.querySelectorAll('[role="grid"] *')].filter(e => e.tabIndex === 0).length)).toBe(1);

Step 5 — Lock in with snapshots (SC 1.3.1)

Permalink to "Step 5 — Lock in with snapshots (SC 1.3.1)"

See ARIA snapshot testing with Playwright.

await expect(page.getByRole('grid', { name: 'Invoices' })).toMatchAriaSnapshot(`- grid "Invoices"`);

Step 6 — Platform APIs for stubborn cases

Permalink to "Step 6 — Platform APIs for stubborn cases"

See reading platform accessibility APIs for grids.

TableItemPattern.ColumnHeaderItems = []   ← why Narrator reads no headers
Diagnosis from report to fix Flow: a bug report arrives; reproduce with the named reader; inspect the browser tree; if wrong, fix markup; if right, inspect the platform API; file upstream with evidence if needed; add a snapshot test to prevent regression. Diagnosis from report to fixReport"NVDA says blank on Status"reader, browser, versionsReproducesame combinationconfirmBrowser treewrong name or role?yes: fix markupPlatform APImapping wrong?file browser bug with evidencePreventARIA snapshot or role query testregression guard

Keyboard interaction contract

Permalink to "Keyboard interaction contract"

Inspection is driven by the same keys users press; reproduce issues by keyboard, not by clicking:

Key Inspect after pressing Typical finding
Tab Which node has focus; is it the grid’s single tab stop? Every cell focusable
Arrows Focused cell’s name and position Empty names; wrong indices
Enter on a header aria-sort on columnheader State on the inner button instead
Enter on an expandable row aria-expanded and new rows State not updated
Shift+F10 Menu role and items Menu without role or names

Screen reader compatibility matrix

Permalink to "Screen reader compatibility matrix"

Inspection explains differences between readers:

Symptom Likely layer Tool
Works in NVDA+Chrome, not NVDA+Firefox Browser mapping Firefox inspector
Works in NVDA, not Narrator Platform patterns Accessibility Insights for Windows
Works in Chrome, not Safari + VoiceOver AX mapping macOS Accessibility Inspector
Wrong in every reader Markup Chrome DevTools
Right in the tree, wrong in one reader only Reader logic Speech log and vendor report

Edge cases & failure modes

Permalink to "Edge cases & failure modes"

1. Fixing names with labels that hide visible text

Permalink to "1. Fixing names with labels that hide visible text"

Diagnosis: aria-label added until DevTools looks right. Fix: let visible text name controls; check SC 2.5.3.

2. Snapshots updated without review

Permalink to "2. Snapshots updated without review"

Diagnosis: regressions accepted as new baselines. Fix: review diffs like code.

3. Tools run on empty states

Permalink to "3. Tools run on empty states"

Diagnosis: FastPass before data loads. Fix: stable, loaded states.

4. Platform debugging first

Permalink to "4. Platform debugging first"

Diagnosis: hours in Inspect.exe on a markup bug. Fix: top-down diagnosis.

5. Missing versions in reports

Permalink to "5. Missing versions in reports"

Diagnosis: “doesn’t work in JAWS”. Fix: reader, browser, OS versions and steps.

Inspecting the accessibility tree in Chrome DevTools

Permalink to "Inspecting the accessibility tree in Chrome DevTools"

Computed roles, names and name sources, ignored nodes and the full-page tree — the first stop for any announcement bug. See inspecting the accessibility tree in Chrome DevTools.

Ignored: aria-hidden is true

Firefox accessibility inspector for data grids

Permalink to "Firefox accessibility inspector for data grids"

Relations, states, tabbing order overlays, built-in checks and colour vision simulation, in the browser NVDA users often prefer. See the Firefox accessibility inspector for data grids.

Show tabbing order → 480 stops in the grid

Accessibility Insights FastPass on data pages

Permalink to "Accessibility Insights FastPass on data pages"

Five-minute automated checks plus Tab stops, run on loaded, filtered, editing and dialog states. See Accessibility Insights FastPass on data pages.

new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag22aa']).analyze()

ARIA snapshot testing with Playwright

Permalink to "ARIA snapshot testing with Playwright"

Readable YAML of a region’s roles, names and states that fails when structure changes. See ARIA snapshot testing with Playwright.

- grid "Invoices":
  - row: [columnheader "Invoice", columnheader "Amount"]

Reading platform accessibility APIs for grids

Permalink to "Reading platform accessibility APIs for grids"

UIA, IA2, AX and ATK inspectors for issues that differ between readers or browsers, with evidence for upstream reports. See reading platform accessibility APIs for grids.

AXSortDirection: AXDescendingSortDirection

Cross-cutting concerns

Permalink to "Cross-cutting concerns"

Evidence in bug reports. A screenshot of the accessibility pane is often the most useful attachment a bug report can have; it shows exactly what was exposed.

Regression tests from fixes. Every inspection that leads to a fix should leave behind a test — an ARIA snapshot, a role query or an attribute assertion — so the bug cannot return.

Performance. Large trees slow screen readers. While inspecting, note node counts for grids; see measuring accessibility tree cost.

Team skills. Inspection is learnable in an afternoon. Teams that train every frontend developer on the DevTools accessibility pane fix issues faster and argue about ARIA less.

From inspection to regression test Sequence among developer, DevTools, code and CI: the developer inspects a cell with an empty name, fixes the markup, re-inspects, then adds an ARIA snapshot that CI runs on every pull request. From inspection to regression testDeveloperDevToolsCodeCIinspect Status cell: nameemptycause: aria-hidden on badgeremove aria-hidden; remove duplicate textname "Overdue" confirmedadd ARIA snapshot for the row
Every fix leaves a test behind.

Worked example: a week of guessing, an hour of inspection

Permalink to "Worked example: a week of guessing, an hour of inspection"

A support grid’s Status column was announced as “blank” by NVDA. Over a week, three developers tried fixes: an aria-label on the cell (which broke the visible text match), role="presentation" on the badge (which hid it), and a visually hidden duplicate (which caused double announcements in VoiceOver). An accessibility specialist then spent an hour with the DevTools accessibility pane: the badge text sat inside an aria-hidden wrapper added to suppress a tooltip. Removing the wrapper and the tooltip duplicate fixed every reader. The team added an ARIA snapshot for the row and a one-page internal guide to the accessibility pane; similar bugs since have taken minutes.

Who is affected, and how

Permalink to "Who is affected, and how"
Who How inspection helps
Screen reader users Bugs fixed at the cause, without side effects
Developers Less guessing; reproducible evidence
QA and auditors Precise reports with tree evidence
Library maintainers Actionable upstream reports
Product teams Fewer regressions thanks to snapshot tests

Common mistakes

Permalink to "Common mistakes"
  • Testing only by ear. Listening to a screen reader shows symptoms; inspecting the tree shows causes.
  • Treating the tree as the output. The tree shows what is exposed, not what readers say; confirm fixes with a reader.
  • Inspecting the default state only. Many bugs appear only in focus, selection, expansion or dialog states.
  • No regression guard. A fix without a test returns at the next refactor.
  • Skipping Firefox. NVDA users often prefer Firefox; mapping differences are real.

Building team skills

Permalink to "Building team skills"

A short internal session covers most of what developers need: open the Accessibility pane, read role, name and states, find the name source, spot ignored nodes, and toggle the full-page tree. Follow it with a practice bug — a cell announced as “blank” — and let developers find the cause. Add the Firefox tabbing order overlay and FastPass to the same session. Teams that do this report fewer speculative ARIA changes and faster fixes, and accessibility reviews shift from “try this” to “here is why”.

Measuring the effect

Permalink to "Measuring the effect"

Track two things before and after introducing inspection practices: the median time from accessibility bug report to fix, and the number of reopened accessibility bugs (fixes that did not work or caused new problems). Both usually fall noticeably once teams diagnose with the tree and leave snapshot tests behind.

Design system integration

Permalink to "Design system integration"

Document the expected accessibility tree for each component state (as ARIA snapshot templates), include them in component tests, and publish them in the component docs. When a product reports a bug, compare its tree with the reference first. Keep a shared log of platform-level findings and workarounds with links to upstream issues.

A reference session for new team members

Permalink to "A reference session for new team members"

When onboarding developers to accessibility work on data UIs, one hour covers the essentials. Open any grid page. In Chrome, toggle the full-page accessibility tree and find the grid; read a header cell, a body cell and an icon button, noting role, name and name source. Break something on purpose — add aria-hidden to a cell’s content — and watch the name disappear. In Firefox, show the tabbing order and count the stops. Run FastPass on the same page. Finally, write a three-line ARIA snapshot for the header row. By the end, each developer has seen every layer of the stack and owns a regression test.

Testing checklist

Permalink to "Testing checklist"

Automated

Permalink to "Automated"

Manual

Permalink to "Manual"

Reporting

Permalink to "Reporting"

FAQ

Permalink to "FAQ"
Do developers need screen readers if they can read the tree?

Yes. The tree shows what is exposed; readers show what users experience. Use both.

Which tool should a team learn first?

The Chrome DevTools accessibility pane. It solves most issues.

Are ARIA snapshots better than axe?

They check different things. Snapshots verify structure you expect; axe checks rules you might not think of.

How do I convince a browser vendor a bug is theirs?

Provide a minimal HTML reproduction, the expected mapping from the AAM spec and the platform inspector output showing the difference.

Can inspection find live region problems?

It shows live region nodes and their content but not whether announcements fired; use speech logs for timing.

Should QA include inspection in test plans?

For complex widgets, yes — attaching tree screenshots to failed test cases speeds up fixes considerably.

How often do platform-level bugs occur?

Rarely compared with markup bugs, but they cluster around complex widgets like grids and treegrids.

Is there a single view of all layers?

No single tool shows every layer; that is why the top-down sequence matters.

How do we keep inspection knowledge from living in one person's head?

Write short internal runbooks with screenshots for each tool, link them from your bug template, and rotate who leads accessibility investigations so several people build the skill.

Should product managers see tree evidence?

A screenshot of an empty name next to the visible text is often what makes the cost of a bug obvious to non-specialists. Include it in tickets.

Which single habit makes the biggest difference?

Opening the accessibility pane before changing any ARIA. It turns every fix into a diagnosis first.

Permalink to "Related"

← Back to Testing & Auditing Accessible Data Interfaces