role=linkBug (ENG-1748): Access Engine test 1321 (label in name — the visible text of a link must appear in its accessible name, WCAG 2.5.3) scoped its candidate set to a[data-ae_vis][data-ae_avat][data-ae_ar="null"][data-ae_an] — anchors with no ARIA role at all. Any role attribute took the anchor out of scope, including role="link", which does not change what the element is. Markup such as <a href="foo" role="link" aria-label="not right">Testing this out</a> was silently skipped — a false negative.
Impact: Speech-input users cannot activate a link by speaking its visible text when the accessible name does not contain it. Design systems and component libraries frequently emit a redundant role="link" on anchors, so every label-in-name failure inside those components went unreported.
A elements without an ARIA-assigned role, or with role=link, not intentionally hidden in the DOM, available to assistive technologies, that have both visible text and an accessible name.< > - . , and the ellipsis are treated as spaces) is applied as a fallback before reporting.role="button", role="presentation", …) remain out of scope — they are no longer being exposed as links.role="link" alongside href.aria-label for screen reader users.aria-labelledby pointing at text other than the link's own.data-ae_computed_role, the explicit-or-implicit ARIA role):
a[data-ae_vis][data-ae_avat][data-ae_ar="null"][data-ae_an], a[data-ae_vis][data-ae_avat][data-ae_computed_role="link"][data-ae_an]
role="link" in any letter case; the original data-ae_ar="null" branch is retained so role-less anchors stay in scope exactly as before — the change only adds coverage, it never removes it. Both branches still require data-ae_an: accessible names are calculated for role-less elements and for [data-ae_ar='link'], so an anchor that only resolves to link through an invalid first role token (role="foo link") has no name to compare against and stays out of scope.
role="button" and a mismatched aria-label other roleThe anchor is exposed as a button, not a link, so test 1321 does not apply. Only role=link (or no role) is in scope. Should not be flagged.
role="presentation" and a mismatched aria-label other roleAn explicit presentational role removes the link semantics the test is about. Out of scope, unchanged by ENG-1748. Should not be flagged.
role="link" hidden with display:none hidden(Anchor is present but hidden via display:none.)
Test 1321 only evaluates elements that are not intentionally hidden: the selector requires [data-ae_vis]. Should not be flagged.
role="link" and aria-hidden="true" not exposedNot available to assistive technologies, so the selector's [data-ae_avat] requirement excludes it. Should not be flagged.
role="link" — no visible text no textWith no visible text there is nothing that must appear in the accessible name; the link's own pseudo content is suppressed when an aria-label supplies the name (ENG-1722). Should not be flagged.
role="foo link" with a mismatched aria-label token listBrowsers skip the unknown token and treat this as a link, and the computed role is link — but accessible names are only calculated for role-less elements and for [data-ae_ar='link'], and data-ae_ar here is foo. With no data-ae_an there is nothing to compare, so the element stays out of scope. Documented gap, not flagged. (Tests 37 and 412 flag this element separately for the invalid role token.)
aria-label contains the visible text no roleVisible text is a substring of the accessible name. Should not be flagged.
role="link" whose aria-label contains the visible text role=linkNewly in scope after ENG-1748, and compliant: the accessible name starts with the visible text. Should not be flagged.
role="link" named by its own text role=linkNo aria-label, so the accessible name is the visible text. Should not be flagged.
role="link" matching only after punctuation normalisation punctuationThe strict substring check fails on the hyphens, but the punctuation-insensitive fallback matches. Should not be flagged.
role="link" anchor with a mismatched aria-label role=linkThe markup from ENG-1748: the accessible name "not right" does not contain the visible text. Pre-fix: not flagged ❌. Post-fix: flagged ✓.
role="LINK" anchor with a mismatched aria-label caseARIA role tokens are case-insensitive and the computed role is normalised to lower case. Pre-fix: not flagged ❌. Post-fix: flagged ✓.
role="link" anchor with no href and a mismatched aria-label no hrefWithout href the anchor has no implicit link role, but the explicit role="link" makes it one — and a speech-input user still says "stay". Pre-fix: not flagged ❌. Post-fix: flagged ✓. (Test 1119 also flags this element for having neither href nor a tabindex — expected and unrelated to test 1321.)
role="link" anchor named by aria-labelledby pointing at other text labelledbyLabel source: Download the 2026 media kit
The accessible name comes from another element and does not contain the visible "Press pack". Pre-fix: not flagged ❌. Post-fix: flagged ✓.
aria-label no roleThe original test 1321 case. Must stay flagged ✓.
href and a mismatched aria-label no role, no hrefIts computed role is empty (no href), so it is only in scope through the retained data-ae_ar="null" branch. This case guards against narrowing the selector to the computed role alone. Must stay flagged ✓. (Test 1119 also flags it for having neither href nor a tabindex — expected and unrelated to test 1321.)
role="link" role=linkA speech-input user says "Read more" but the accessible name never contains it. Pre-fix: not flagged ❌. Post-fix: flagged ✓.
role="link" whose label drops the visible heading text role=linkThe shortened label omits the visible product name. Pre-fix: not flagged ❌. Post-fix: flagged ✓.