Reading Platform Accessibility APIs for Grids

Permalink to "Reading Platform Accessibility APIs for Grids"

Screen readers do not read the DOM, or even the browser’s internal accessibility tree; they read platform accessibility APIs — UI Automation (UIA) and IAccessible2 on Windows, the AX API on macOS and iOS, ATK/AT-SPI on Linux. Browsers translate ARIA into those APIs according to the Accessibility API Mappings specs. Most bugs are in markup and show up in browser DevTools. The stubborn ones — “it works in NVDA but not Narrator”, “VoiceOver ignores aria-sort” — need a look at the platform layer to decide who should fix what.

This guide belongs to accessibility tree & API inspection.

Spec reference

Permalink to "Spec reference"
  • Core-AAM, HTML-AAM — map ARIA roles, states and properties and HTML elements to UIA, IAccessible2, AX API and ATK. For example, role="grid" maps to a UIA DataGrid control type with Grid and Table patterns; aria-sort maps to UIA ItemStatus or a custom property in some browsers and to AXSortDirection on macOS.
  • UIA patterns — Grid, Table, GridItem, TableItem, SelectionItem, ExpandCollapse; screen readers like Narrator rely on them for table navigation.
  • macOS AX attributes — AXRole, AXSubrole, AXRowCount, AXColumnHeaderUIElements, AXSortDirection, AXDisclosing.
From ARIA to speech Layers: author markup with ARIA; the browser's internal accessibility tree; the platform API (UIA, IA2, AX, ATK); the screen reader's own model; and speech or braille output. From ARIA to speechMarkuprole="grid", aria-sort, aria-expandedBrowser treeChrome DevTools, Firefox inspectorPlatform APIUIA patterns, IA2, AX attributes, ATKScreen reader modelNVDA, JAWS, VoiceOver, Narrator, Orca logicOutputspeech and braille the user receives
Bugs can live at any layer; inspectors show each one.

When to use — and when not to

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

Inspect platform APIs when the browser tree is correct but one screen reader or one browser behaves differently, and before filing bugs against browsers or screen readers — maintainers need platform-level evidence.

Do not start here. Check markup and browser trees first; most issues end there. The misapplication: spending a day in Inspect.exe on a problem caused by a missing scope attribute.

Platform inspectors and what they show Matrix of inspectors — Accessibility Insights for Windows, Inspect (Windows SDK), macOS Accessibility Inspector, Accerciser — against the API they read, grid-relevant information and typical use. Platform inspectors and what they showAPIGrid informationTypical useAccessibility Insights forWindowsUIAControl types andpatternsNarrator and JAWS issuesInspect (Windows SDK)UIA and MSAAProperties and patternsDetailed property checksmacOS AccessibilityInspectorAX APIRows, columns, headers,sortVoiceOver issuesAccerciserATK/AT-SPITable interfacesOrca on Linux
Pick the inspector for the platform where the bug appears.

Deciding who fixes it

Permalink to "Deciding who fixes it"
Deciding where a bug lives Flow: is the ARIA correct per spec? If not, fix markup. Does the browser tree show it correctly? If not, file a browser bug. Does the platform API expose it per AAM? If not, file a browser bug with API evidence. If yes, and the reader still fails, file a screen reader bug. Deciding where a bug livesMarkup per spec?validate roles, states, relationshipsno: fix your codeBrowser tree correct?DevTools or Firefox inspectorno: browser bugPlatform API per AAM?UIA, AX or ATK inspectorno: browser mapping bugReader uses it?speech log differs from APIscreen reader bugWorkaround needed?document and test ittrack removal later

Annotated code example

Permalink to "Annotated code example"

Example investigation: Narrator does not announce column headers in a custom grid, NVDA does.

<div role="grid" aria-label="Invoices" aria-rowcount="241">
  <div role="row">
    <div role="columnheader">Invoice</div><div role="columnheader">Amount</div>
  </div>
  <div role="row">
    <div role="gridcell">INV-1042</div><div role="gridcell">1,240.00</div>
  </div>
</div>

In Accessibility Insights for Windows (Live Inspect), select a cell:

ControlType: DataItem
GridItemPattern: Row=1, Column=1        ← present
TableItemPattern: ColumnHeaderItems = [] ← empty: Narrator has no header to read

Adding rowgroup wrappers and moving the header row into its own rowgroup (as many browsers expect for header association), or using a native table with role="grid", populates ColumnHeaderItems:

<div role="grid" aria-label="Invoices">
  <div role="rowgroup"><div role="row"><div role="columnheader">Invoice</div>…</div></div>
  <div role="rowgroup"><div role="row"><div role="gridcell">INV-1042</div>…</div></div>
</div>

The exact requirements vary by browser version; the inspector tells you whether the fix worked for the platform your users are on.

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Symptom Layer to inspect What to look for
Narrator skips headers UIA TableItem ColumnHeaderItems
VoiceOver ignores sort macOS AX AXSortDirection on the header
JAWS reads “row 0” UIA / IA2 Row index attributes
Orca reads no table ATK Table interface present
Expand state missing UIA ExpandCollapse / AX AXDisclosing Pattern or attribute present
Time spent per layer in a typical stubborn bug Bar chart of investigation time: markup review 10 minutes, browser tree 10 minutes, platform API inspection 20 minutes, writing a minimal reproduction and bug report 30 minutes. Time spent per layer in a typical stubborn bugMarkup reviewfind spec violations firstBrowser treeDevTools or Firefox inspectorPlatform APIUIA, AX or ATK inspectorReproduction and reportminimal test case with evidence
Platform inspection is short once you know where to look; the reproduction is the real work.

Integration context

Permalink to "Integration context"

Start with browser-level tools: inspecting the accessibility tree in Chrome DevTools and the Firefox accessibility inspector. Known reader differences are documented in assistive technology behaviour differences, including Narrator and Edge with data grids. Turn findings into actionable reports with writing actionable accessibility bug reports.

Gotchas

Permalink to "Gotchas"

Browser versions. Mappings change between browser versions. Record versions in every finding.

Virtual buffers. NVDA and JAWS build virtual buffers from IA2/UIA; some behaviour depends on browse versus focus mode, not on API values alone.

Permissions. macOS Accessibility Inspector and some Windows tools need accessibility permissions; corporate machines may block them.

Common mistakes

Permalink to "Common mistakes"
  • Starting at the platform layer before checking markup.
  • Filing reader bugs without API evidence.
  • Not recording browser, reader and OS versions.
  • Adding workarounds without tracking when to remove them.

Framework notes

Permalink to "Framework notes"

Framework choice rarely matters at this layer — the browser maps the final DOM. What matters is the rendered structure: wrapper elements with roles, display: contents (which historically removed roles in some browsers), and shadow DOM boundaries. When a component library’s grid behaves differently in one reader, platform inspection gives the evidence the library maintainers need.

Worked example

Permalink to "Worked example"

A grid announced column headers in NVDA and JAWS but not in Narrator. Browser trees in Chrome and Edge looked identical. Accessibility Insights for Windows showed empty ColumnHeaderItems on cells, while NVDA was inferring headers from row and column positions. The team restructured the grid with rowgroups, confirmed populated ColumnHeaderItems in the inspector, and verified with Narrator. They also filed a minimal reproduction with the browser, attaching the inspector output.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Keep a log of platform-level findings per component (browser, reader, versions, workaround, upstream bug link). It saves future teams from re-investigating and tells you when workarounds can go.

FAQ

Permalink to "FAQ"
Do I need these tools for everyday development?

No. Browser DevTools are enough most of the time. Platform tools are for stubborn, reader-specific issues.

Which Windows tool should I use?

Accessibility Insights for Windows is friendlier; Inspect from the Windows SDK shows more raw properties.

How do I inspect iOS?

Use the Accessibility Inspector in Xcode connected to a device or simulator, which reads the AX tree of Safari content.

Can I automate platform API checks?

Rarely worth it for web apps. Use them for investigation and keep automated tests at the browser level.

Where do I report browser mapping bugs?

In the browser’s issue tracker, with a minimal HTML reproduction, the inspector output and the expected mapping from the AAM spec.

What if the bug is in the screen reader?

File with the vendor (NVDA’s GitHub, Freedom Scientific support, Apple Feedback, Microsoft Feedback Hub) and implement a temporary workaround if users are blocked.

Do I need administrator rights to use these tools?

Accessibility Insights for Windows and Inspect run without special rights on most machines. On macOS, the Accessibility Inspector may need accessibility permissions granted in System Settings.

Is this relevant for mobile?

Yes. iOS uses the same AX concepts as macOS (inspect with Xcode’s Accessibility Inspector), and Android exposes AccessibilityNodeInfo, visible with tools in Android Studio, for TalkBack issues.

Permalink to "Related"

← Back to Accessibility Tree & API Inspection