Expectation
Given the following HTML, axe should not report a label-content-name-mismatch violation:
<a aria-label="Deque" href="/">
<img alt="Logo" width="100" src="logo.svg" />
<span>Deque</span>
</a>
The visible text is "Deque" and the aria-label is "Deque" — these match. The image alt text "Logo" is not visible on screen.
Actual
axe reports a label-content-name-mismatch violation: "Text inside the element is not included in the accessible name."
Root cause
The evaluate function in lib/checks/label/label-content-name-mismatch-evaluate.js uses subtreeText() to determine "visible text." However, subtreeText computes the accessible text from content (per the AccName algorithm), not the visually rendered text. For each child, it calls accessibleTextVirtual(), which includes:
In this case, subtreeText returns "Logo Deque" (including the img alt), which does not match the aria-label "Deque".
By contrast, the matches function correctly uses visibleVirtual(), which only collects actual text nodes rendered on screen.
Additional context
Related issues sharing the same root cause (subtreeText including non-visual text in the "visible text" computation):
Potential solution
Replace subtreeText() with visibleVirtual() in the evaluate function to compare only on-screen text against the accessible name. This fixes false positives where image alt text, SVG titles, or visually-hidden text inflate the "visible text" string. Icon ligature filtering can be handled as a separate step using isIconLigature, following the existing pattern in color-contrast-matches.js. Both visibleVirtual and isIconLigature are already available in commons/text. This should also resolve the related issues #4065 and #4678.
Expectation
Given the following HTML, axe should not report a
label-content-name-mismatchviolation:The visible text is "Deque" and the
aria-labelis "Deque" — these match. The image alt text "Logo" is not visible on screen.Actual
axe reports a
label-content-name-mismatchviolation: "Text inside the element is not included in the accessible name."Root cause
The evaluate function in
lib/checks/label/label-content-name-mismatch-evaluate.jsusessubtreeText()to determine "visible text." However,subtreeTextcomputes the accessible text from content (per the AccName algorithm), not the visually rendered text. For each child, it callsaccessibleTextVirtual(), which includes:nativeTextAlternative)In this case,
subtreeTextreturns"Logo Deque"(including the img alt), which does not match thearia-label"Deque".By contrast, the matches function correctly uses
visibleVirtual(), which only collects actual text nodes rendered on screen.Additional context
Related issues sharing the same root cause (
subtreeTextincluding non-visual text in the "visible text" computation):Potential solution
Replace subtreeText() with visibleVirtual() in the evaluate function to compare only on-screen text against the accessible name. This fixes false positives where image alt text, SVG titles, or visually-hidden text inflate the "visible text" string. Icon ligature filtering can be handled as a separate step using isIconLigature, following the existing pattern in color-contrast-matches.js. Both visibleVirtual and isIconLigature are already available in commons/text. This should also resolve the related issues #4065 and #4678.