role-img-text-alternative-present
[role="img"/"graphics-symbol"/"graphics-document"] must have an accessible text alternative
Checks that elements with role="img", "graphics-symbol" or "graphics-document" provide an accessible text alternative using aria-label, aria-labelledby, a title attribute, or (for SVG elements) a child <title>.
Applies to. Applies to elements whose role attribute resolves to img, graphics-symbol or graphics-document (the first known role token of the fallback list, matched in any case) that are included in the accessibility tree (ACT 23a2a8's "programmatically hidden" exemption: display:none/visibility:hidden/aria-hidden="true" on the element or an ancestor, with no carve-out for focusable or IDREF-referenced elements, aria-hidden-focus and duplicate-id-aria own those separately). Per ACT 7d6734, this reaches any element carrying one of these roles, not only the <svg> root, e.g. a <circle role="graphics-symbol"> nested inside a plain <svg>. Every <svg> element itself is left to svg-text-alternative-present's own (already ACT-clean) title/aria-name handling, so an unnamed <svg role="img"> is reported once, there; the <img> tag is excluded here since it has its own dedicated rule. A custom element whose ElementInternals give it one of those roles (this.attachInternals().role), with no role attribute naming another, is in scope too: that is its default role, and no other rule checks it.
Expectation. Each applicable element has an accessible text alternative:
- aria-label with a non-empty value; OR
- aria-labelledby referencing at least one existing element that contributes non-empty text; OR
- a non-empty title attribute (last-resort accessible-name source per HTML-AAM); OR
- for an SVG-namespace element, a non-empty direct child <title>, wherever it is among the children (SVG-AAM's own naming mechanism, not only for the <svg> root); the first one counts.
What a finding reports.
ariaLabel: the element'saria-labelwith surrounding whitespace removed, or null when it has none.ariaLabelledby: the element'saria-labelledbyid list with surrounding whitespace removed, or null when it has none.accessibleNameInfo(nameNotResolved): the accessible name the element ends up with:present,value,mechanism(where the name came from, such asaria-labelledby) andflags(notes on what went wrong, such asidref-missingfor a reference to an id that does not exist). Null on the other findings.
These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.
Examples
<span role="img" aria-label="Notifications"></span>
aria-label provides the text alternative.
<span role="img">notifications</span>
Text content is not a valid name source for an element with an explicit role="img".
How to check
When this rule can’t decide, it reports cantTell and leaves the question to a person. Each question it can ask is listed here under its reason code, with the steps to answer it. A finding carries the same steps as howToCheck, in the scan’s language. See Output schema.
name_internals
- Inspect the image the report names, a custom element, and note its role.
- Open the Accessibility pane in the browser's developer tools and read the element's accessible name.
- With a screen reader, move to the element and listen to the name announced.
Pass. The accessibility tree shows a name for the image, set through its internals or otherwise, and the screen reader announces it.
Fail. The image has no name in the accessibility tree and the screen reader announces only its role, which fails WCAG 1.1.1.