presentation-role-conflict

Presentational role must not conflict with a global ARIA attribute or focusability

manualconfidence: mediumseverity: minorrobust

Checks that role="presentation"/"none" (including an <img alt=""> implicit presentation role) is not combined with a global ARIA attribute (aria-label, aria-hidden, aria-describedby, ...) or focusability (tabindex/native).

Applies to. Applies to elements whose role attribute resolves to presentation or none (the first token naming a known role, matched case-insensitively, so role="foo none" and role="NONE" count), OR an <img alt=""> carrying no explicit role of its own (empty alt gives an <img> an implicit presentation role per HTML-AAM, even with no explicit role attribute at all: img[alt=''], [role~="none" i], [role~="presentation" i]).

Expectation. The element does not also carry a WAI-ARIA global state/property (aria-label, aria-hidden, aria-describedby, aria-live, aria-current, ...; the full global-attribute set, not just the naming ones), AND is not focusable. Per the WAI-ARIA spec's Presentational Roles Conflict Resolution section, a presentational role is "restored" to the element's implicit semantic role when either condition holds: the presentation/none role silently stops working, contradicting the author's evident intent to hide the element from the accessibility tree.

What a finding reports.

  • role: the presentational role in effect: presentation or none. An <img alt=""> with no role of its own reports presentation.
  • conflictingAttrs: the global ARIA attributes the element carries, whatever their value. One item is an attribute name, such as aria-label. Empty when the element has aria-hidden="true" or only its focusability conflicts.
  • focusable: true when the element can take focus, which also restores its role.

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

pass
<div role="presentation">Decorative</div>

No conflicting naming attribute is present alongside the presentation role.

can't tell
<div role="presentation" aria-label="Conflicting">Content</div>

role="presentation" asks assistive technology to skip this element, but aria-label supplies a name — per WAI-ARIA conflict resolution, the global attribute wins and the presentation role is dropped, so the element (and its name) come back into the tree unexpectedly.

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.

PRESENTATION_ROLE_CONFLICT

  1. Find the element the report names; it has role="presentation" or "none", or is an img with alt="".
  2. Note the conflicting aria-* attributes the report lists, and whether it says the element can take focus.
  3. Open the Accessibility pane of the developer tools and see which role and name the element really exposes.
  4. Decide what was meant: if it is decorative, remove the aria-* attribute and the focusability; if it carries meaning, remove the presentational role (or give the image real alt text).

Pass. The element is either purely decorative with no global aria-* attribute and no focus, or it keeps its real role on purpose.

Fail. The element is meant to be hidden but its aria-* attribute or focusability brings its role back, so assistive technology exposes it anyway (best practice, WAI-ARIA presentational roles conflict resolution).

View source