Unique IDs for ARIA references
What it checks
aria-labelledby / aria-describedby / for resolve by id. Duplicate ids make resolution ambiguous, so an agent may read the wrong label or description.
Why it matters
aria-labelledby, aria-describedby and for resolve an IDREF by id lookup, which returns the first element in tree order. When two elements share an id, the accessible name computed per accname — the one exposed in the accessibility tree an agent reads — is taken from the first occurrence. A control referencing the second one is therefore announced with the wrong label.
Evidence
getElementById: “IDs should be unique inside a document. If two or more elements in a document have the same ID, this method returns the first element found” — developer.mozilla.org/…/getElementById (verified 2026-08-21)- Accessible Name and Description Computation 1.1 is a W3C Recommendation of 18 December 2018. It defines the LabelledBy step: “For each IDREF: Set the current node to the node referenced by the IDREF… Compute the text alternative of the current node” — w3.org/…/accname-1.1 (verified 2026-08-21). The same step text is carried in the 1.2 Working Draft — w3.org/…/accname-1.2 (verified 2026-08-21)
- Playwright ARIA snapshots serialise each node’s role and accessible name for the model — playwright.dev/…/aria-snapshots (verified 2026-08-21)
- Playwright MCP and Chrome DevTools MCP both address elements by reference/uid taken from an accessibility-tree snapshot, so a wrong name is what the agent selects on — github.com/…/playwright-mcp and github.com/…/tool-reference.md (both verified 2026-08-21)
- axe rule: the id “must be unique to prevent the second instance from being overlooked by assistive technology”; “only the first instance gets acted upon by client-side scripting” (impact: critical) — dequeuniversity.com/…/duplicate-id-aria (verified 2026-08-21)
Limits
Deque frames the effect as the second instance being overlooked rather than misresolved. The harm materialises only when a duplicated id is actually the target of an ARIA reference or a for attribute. A duplicated id that nothing references changes nothing in the accessibility tree. Duplicate ids from repeated third-party embeds are true positives the site owner cannot fix. Independently of the signal’s grade, this audit as wired can essentially never report the failure: reviewOnFail turns it into an incomplete result, which another page’s pass then overrides.
How it scores
Id resolution (first element in tree order) and the accname IDREF traversal are both ratified, universally implemented behavior, and role + accessible name is precisely what documented agent snapshot tools serialise for the model.
Sources
- MDN — Document.getElementById() — MDN, vendor-doc (verified 2026-08-21)
- Accessible Name and Description Computation 1.1 — W3C, spec (verified 2026-08-21)
- Accessible Name and Description Computation 1.2 — W3C, spec (verified 2026-08-21)
- Live Chromium accessibility snapshot of a probe page (own experiment) — Own experiment via Playwright MCP + Chromium, study (verified 2026-08-21)
- microsoft/playwright-mcp README — Microsoft, vendor-doc (verified 2026-10-20)
- Chrome DevTools MCP — tool reference — Google / Chrome DevTools, repo (verified 2026-08-21)
- axe rule — duplicate-id-aria — Deque, vendor-doc (verified 2026-08-21)
- Browser use tool (browser_toolset_20260801) — Anthropic, vendor-doc (verified 2026-10-20)
Browser view
Anthropic’s find searches “for elements matching a natural-language description such as ‘search field’ or ‘add to cart button’”, and form_input will “Set a form element’s value directly” on the element it returns (verified 2026-10-20). A for, aria-labelledby or aria-describedby reference to a duplicated id resolves to the first element with that id, so the name find matches against can belong to the wrong control. A supplied browser snapshot is the rendered DOM those tools read, so the browser view runs this audit on it.
The browser view runs on each complete, unredacted, non-loading capture that carries readable text and whose accessibility rule pass completed. The pass runs the audit’s rules over the capture HTML with page scripts off and no resource loading. A pass with no results records missing evidence instead of a verdict. The finding is informative with weight 0. It does not prove HTTP delivery, computed appearance, a complete accessibility tree, live form state, or action success. A truncated, redacted or still-loading capture records missing evidence. Existing implementation limits still apply.
The review appears in Browser-rendered snapshot assessment. The eligibility record lives in packages/core/src/snapshot-eligibility.ts. The crawler grade, tier and weight stay unchanged.