role=presentation is no alternative for aria-hidden=true

posted on

This post is part of a series called #WebAccessibilityFails, where I collect common issues I find in accessibility audits so that you can avoid them in the future.

In the previous post, I explained how to hide presentational SVGs using aria-hidden="true".
That's a reliable technique, but sometimes I see developers use role="presentation" instead, which may or may not work as expected.

Before I show you where it fails, let's first try to understand the difference between role="presentation" and aria-hidden="true".

aria-hidden="true"

According to the spec, aria-hidden indicates, when set to true, that an element and its entire subtree are hidden from assistive technology, regardless of whether it is visibly rendered.

The following heading is visually accessible, but hidden from assistive technology.

<h2 aria-hidden="true">
    Hello World
</h2>

The same applies to the following SVG.

<svg viewBox="0 0 39 44" aria-hidden="true">
  <text x="20" y="35">🥔</text>
</svg>

Screen readers skip both elements entirely and don't announce anything.

role="presentation"

According to the spec, the native role semantics of an element with role="presentation" (or role="none", which is a synonym) will not be mapped to the accessibility API.

This means that the main difference from aria-hidden="true" is that role="presentation" only removes the native role of an element, not the element or its children.

Instead of something like "heading level 2, Hello World" a screen announces “Hello World” only. So, in terms of semantics, this element isn't a heading anymore but just static text.

<h2 role="presentation">
    Hello World
</h2>

Images are different

Images are an exception, as noted in the ARIA specification.

In HTML, the <img> element is treated as a single entity regardless of the type of image file. Consequently, using role="none" or role="presentation" on an HTML img is equivalent to using aria-hidden="true".

Just because that's true for images doesn't mean that it's always true for SVGs.

Where role="presentation" fails (your expectations)

If you put role="presentation" on an unlabelled SVG without any text nodes, VoiceOver, Talkback, JAWS, and NVDA will ignore it.

<svg viewBox="0 0 39 44" role="presentation">
  <path d="M19.5 36.5 1.6 26.1v-3.6l16.3 9.4V1.5h3.2v30.4l16.3-9.4v3.6z"/>
</svg>

So, that's fine, but if you provide an accessible name for the SVG, all screen readers I tested, except JAWS, announce the SVG regardless of role="presentation".

<svg viewBox="0 0 39 44" role="presentation" aria-label="Download">
  <path d="M19.5 36.5 1.6 26.1v-3.6l16.3 9.4V1.5h3.2v30.4l16.3-9.4v3.6z"/>
</svg>

For example, VoiceOver on macOS announces “Download, group” or NVDA with Chrome “graphic, download".

If your SVG contains text, all screen readers announce the text.

<svg viewBox="0 0 39 44" role="presentation">
  <text x="20" y="35" class="small">🥔</text>
</svg>

You can see how role=presentation doesn't always remove an element entirely from the accessibility tree.

Conclusion

If you want to remove an element from the accessibility tree, use aria-hidden="true". For img elements, you can use an empty alt attribute, alt="". Although role=presentation works for images, too, avoid it to avoid causing confusion with your colleagues.

PS: Screen readers used for testing: VoiceOver, macOS 26.3, Chrome 145, VoiceOver, macOS 26.3, Safari, Talkback, Android 16, Chrome 145, JAWS 2026, Windows 11, Chrome 145, NVDA 2025.3.3, Windows 11, Chrome146, NVDA 2025.3.3, Windows 11, Firefox 147, Narrator, and Windows 11, Edge .