Jump to main content

Know your ARIA: 'Hidden' vs 'None'

  • Published:
  • Category: accessibility

A primer on appropriately using aria-hidden='true' and role='none/presentation'. They each do very different things to elements, but their purposes are sometimes confused by developers.

What does aria-hidden do?

The aria-hidden attribute indicates whether an element is exposed to an accessibility API. If an element has aria-hidden set to “true”, the element, and any of its children, should not be exposed to the accessibility API, regardless of whether the element is visually rendered or not. Setting the attribute to “false” should expose the element, but as noted in the ARIA 1.1 spec, there may be issues with using aria-hidden="false. Setting aria-hidden without a value will default to the current state of the element, meaning that if it is currently exposed to the accessibility API, then it will continue to do so, where as if the element is not exposed, it will continue to not be exposed if an aria-hidden with an empty string is used.

When to use aria-hidden="true"

In most cases, if content is being hidden from users, that content should be hidden from all users. In those scenarios, aria-hidden="true" may not really be the appropriate attribute. For instance, one could instead use CSS to set an element to display: none or visibility: hidden. Doing so will visually hide content, as well as remove it from being discovered by assistive technologies. Alternatively, the HTML hidden attribute could be used, which will keep content hidden even in instances where CSS may become unavailable (for example, a browser’s reader mode). aria-hidden by itself is not enough to completely hide an element from all users, if that is the end goal.

For instance, the following is hidden to assistive technologies, but it is not visually hidden with the use of aria-hidden alone.

<p aria-hidden="true">
  This content is not announced to screen readers.
</p>

Using aria-hidden in this manner can be confusing for sighted or partially sighted users who may also rely on assistive technologies. There’s clearly content there… why isn’t it being announced?

For comparison, the following examples are completely hidden to all users:

<p hidden>...</p>
<p style="display: none;">...</p>
<p style="visibility: hidden;">...</p>

If the intent is to use aria-hidden to hide content from all users, it’s advised to pair its usage with one of the CSS methods demonstrated above, or to just use the hidden attribute instead.

Instances where aria-hidden="true" should be used without also visually hiding the element it is set on, are when an element contains content that could be considered decorative, or duplicative, to equally accessible content that is rendered on the page.

A simple example would be a link containing a SVG or font icon along with visually rendered text. An icon in this situation would be redundant to the text, so it would be better hidden to assistive technologies.

<a href="/">
  <span class="font-icon font-icon--home" aria-hidden="true"></span>
  Home
</a>

What does role="none" and role="presentation" do?

Where aria-hidden can be used to completely hide content from assistive technology, modifying an element’s role to “none” or “presentation” removes the semantics of the element, but does not hide the content from assistive technologies. Additionally, setting a parent element’s role to one of these values does not change the semantics of any element that may be a child with the modified role, where setting aria-hidden="true" to a parent element will hide all children of that element.

Note: role="presentation" and role="none" are meant to do exactly the same thing. “None” is merely a synonym role that was introduced in ARIA 1.1. As noted in the ARIA 1.1 specification:

In ARIA 1.1, the working group introduced none as a synonym to the presentation role, due to author confusion surrounding the intended meaning of the word "presentation" or "presentational." Many individuals erroneously consider role="presentation" to be synonymous with aria-hidden="true", and we believe role="none" conveys the actual meaning more unambiguously.

Until implementations include sufficient support for role="none", web authors are advised to use the presentation role alone role="presentation" or redundantly as a fallback to the none role role="none presentation".

When to use role="none/presentation"

Ideally you wouldn’t need to use these roles too often, since they completely negate the semantics of any element they are attached to, and hopefully one isn’t using an element with meaningful semantics for layout purposes (maybe use a div instead?). But there are very legitimate instances where one should utilize these roles to negate semantics that may not be appropriate.

For instance, using table elements for layout purposes. Thankfully, this is largely a practice that has been eradicated from modern web practices. However, that doesn’t mean that there aren’t still some legacy web applications that were setup as tables, even though they really shouldn’t have been.

To mitigate misuse like this, layout tables can have their semantics removed by setting the role="presentation" to the table elements, making such content (hopefully) less confusing for screen reader users to parse.

Alternatively, the use of role="presentation" can be used when progressively enhancing an appropriately marked up pattern, if no JavaScript is available, to an expected pattern for use in certain ARIA patterns. For example, a tab panel:

<ul>
  <li><a href="#panel_1">...</a></li>
  <li><a href="#panel_2">...</a></li>
  <li><a href="#panel_3">...</a></li>
</ul>

The above markup shows what a listing of tabs would look like if JavaScript weren’t available, as this content could render like a table of contents in such a situation.

However, where an unordered list has a child li which then contains the actionable a element, a tablist is only meant to be the wrapper element, and then the child tab elements are meant to be actionable themselves. In regards to the previous markup example, this leaves the lis as unnecessary and actually inappropriate for a tablist. But this is where the role="presentation/none" becomes useful, as the markup pattern can be revised to the following:

<ul role="tablist">
  <li role="presentation">
    <a href="#panel_1" 
      role="tab"
      aria-selected="true/false" 
      aria-controls="panel_1">
      ...
    </a>
  </li>
  <!-- etc. -->
</ul>

With the role="presentation" set, the semantics of the li are not exposed, and the tabs are exposed to the accessibility API in the expected format for a tablist.

Wrapping up

ARIA can be incredibly helpful in making document and interfaces accessible, especially when filling in semantic gaps of native HTML. However it must be mentioned time and time again that no ARIA is better than bad ARIA.

If you’re going to use ARIA to augment your HTML, it behooves you to ensure its proper usage. For instance, neither aria-hidden="true" or role="presentation" are particularly appropriate for hiding img elements. To hide an image from assistive technologies, all one needs to do is set the img’s alt attribute to the empty string.

Sometimes it may just take a quick step back to think about what it is you’re trying to do. For more information on how hide content for all users, check out my previous article, “Inclusively Hidden”.