HTML5 Accessibility Chops: hidden and aria-hidden

Latest Update: The state of hidden content support in 2016

As a developer and also a consultant advising developers on how to develop accessible content, it is important to have and provide up to date and practical knowledge about robust development techniques. A recent question on Stack Overflow got me thinking: What is the best method for hiding content for all users? For hiding content for some users?

The standard technique for hiding content for all users has been the use CSS display:none. Now, both ARIA and HTML5 also provide a semantic indication of content state that indicates content is hidden or should not be available to users:

HTML5 hidden

The HTML5 hidden attribute provides a semantic indicator:

All HTML elements may have the hidden content attribute set. The hidden attribute is a boolean attribute. When specified on an element, it indicates that the element is not yet, or is no longer, relevant. User agents should not render elements that have the hidden attribute specified.

Example code:

<p hidden>This content is hidden.</p>

HTML5 hidden effects:

  • In supporting browsers the content is not displayed to any user.
  • semantic indicator of state in HTML code (hidden attribute)
  • CSS style of display:none applied by browser.
  • Focusable content is not included in tab order.
  • Not included in the accessibility tree.

aria-hidden

Indicates that the element and all of its descendants are not visible or perceivable to any user as implemented by the author.

Example code:

<p aria-hidden="true">This content is hidden.</p>
<p aria-hidden="false">This content is not hidden.</p>
<!-- aria-hidden="false" is same as -->
<p aria-hidden="true">This content is hidden.</p>
<p>This content is not hidden.</p>

aria-hidden effects:

  • In supporting browsers in conjunction with supporting assistive technology the content is not conveyed to the user via the assistive technology.
  • Content is displayed in the browser.
  • semantic indicator of state in HTML code (aria-hidden attribute)
  • In some browsers its not included in the accessibility tree in other browsers it is included in the accessibility tree.
    • For browser that include aria-hidden content in the accessibility tree focusable content is included in tab order and is navigable and operable for AT users (as well as other users).
  • In browsers that do include the content in the accessibility tree the content has an accessible MSAA (if supported) state of invisible. If IA2 is supported aria-hidden=true is passed as an object attribute. If UIA is supported aria-hidden=true is passed as an ARIA property.
  • aria-hidden=false is not mapped in any browser that supports aria-hidden, thus its use has no meaning or in other words has the same meaning as its absence.

CSS display:none

As mentioned, the standard method to hide content from all users in browsers that support CSS is and has been to use CSS display:none.

Example code:

<p style="display:none">This content is hidden.</p>

display:none effects:

  • In supporting browsers the content is not displayed to any user.
  • Focusable content is not included in tab order.
  • Not included in the accessibility tree (except for IE)
  • In IE the content has an accessible MSAA (if supported) state of invisible.  If UIA is supported OffScreen=true.

Recommendations:

Hiding content from all users

If you want to hide content from all users, use the HTML5 hidden attribute (along with CSS display:none for browsers that do not yet support hidden) There is no need to use aria-hidden.

Example code:

.hidden {display:none}
<p hidden class="hidden">this content is hidden from all users</p>

Hiding non interactive content from visible display

Use an off screen technique to remove content from visible display, but still available to screen reader users:

Example code:

.offscreen
 {
 clip-path: inset(100%);
 clip: rect(1px, 1px, 1px, 1px);
 height: 1px;
 overflow: hidden;
 position: absolute;
 white-space: nowrap; /* added line */
 width: 1px;
 }

<div class="offscreen">This text is visually hidden.</div>

Modified example code from: WebAIM – CSS in Action: Invisible Content Just for Screen Reader Users

Updated code examples, October 2016,  to take into account new advice from Jessica Beach: Beware smushed off-screen accessible text

Hiding interactive content from visible display

Hiding interactive (focusable) content from visible display using the off screen technique means it is not visible, but still  in the tab order and causes issues for keyboard only users. Focusable content should only be hidden from visible display if the focusable element becomes visible when it receives focus:

Example code:

a.offscreen
{
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap; /* added line */
width: 1px;
 }

a.offscreen:focus
 {
position:relative;
clip:auto;
width:auto;
height:auto;
overflow:auto;
 }

<a class="offscreen" href="test.html">this link is offscreen unless it has focus</a>

Notes by Ted Drake, on use of the off screen technique described:

Using negative position can create long scroll bars when localizing a site for a rtl language. Also, it uses CSS properties that are commonly used and easy to accidentally over-ride.

The Yahoo Accessibility Lab recommends using clip for content that should be hidden from the visual user, yet available to screen reader users. Thierry Koblentz has a great article on this technique, as well as the underlying philosophy behind using the correct CSS techniques for hiding content. Clip your hidden content for better accessibility

The tests

Support for aria-hidden, HTML5 hidden and the off screen technique was tested using JAWS, Window Eyes and NVDA (Windows), ChromeVox (Chrome OS), VoiceOver (iOS and Mac OSX) and Orca (Linux) with supporting browsers for each OS.

Result summary

  • Use of HTML5 hidden (+ CSS display:none) worked in all screen reader/browser combinations tested.
  • Use of the off screen technique worked in all screen reader/browser combinations tested.
  • Use of aria-hidden=true worked in some screen reader/browser combinations tested.
  • Use of aria-hidden=false had no effect in any of the screen reader/browser combinations tested. In other words if content is hidden from all users using HTML5 hidden or display:none applying aria-hidden=false to the content does not make it visible to screen reader users.

Detailed tests and test results are available -updated 11/2013.

further reading:

Providing Context for Ambiguous Link Phrases

Categories: Technical

About Steve Faulkner

Steve was the Chief Accessibility Officer at TPGi before he left in October 2023. He joined TPGi in 2006 and was previously a Senior Web Accessibility Consultant at vision australia. Steve is a member of several groups, including the W3C Web Platforms Working Group and the W3C ARIA Working Group. He is an editor of several specifications at the W3C including ARIA in HTML and HTML Accessibility API Mappings 1.0. He also develops and maintains HTML5accessibility and the JAWS bug tracker/standards support.

Comments

Jared Smith says:

Did you happen to test HTML5 hidden alone? I would think that using it alone should be the ultimate goal, once it has sufficient support. And I’d also think that support should be entirely browser-specific (screen readers shouldn’t need to do anything special if browsers hide the content correctly), right?

Of note with aria-hidden=”false” is the the false assumption that you can use it unhide portions of content within something that is hidden (e.g., embedding aria-hidden=”false” content within a larger aria-hidden=”true” element).

Great post!

Steve Faulkner says:

Hi Jared,
HTML5 hidden alone is test 2. I have only advised to use in conjunction with display:none until IE starts supporting it. Note that hidden is implemented in browsers by applying display:none to the hidden content.

And I’d also think that support should be entirely browser-specific (screen readers shouldn’t need to do anything special if browsers hide the content correctly), right?

Agreed.

Of note with aria-hidden=”false” is the the false assumption that you can use it unhide portions of content within something that is hidden (e.g., embedding aria-hidden=”false” content within a larger aria-hidden=”true” element).

This is the false assumption I have attempted to debunk.

Ted Drake says:

Hi Steve
Using negative position can create long scroll bars when localizing a site for a rtl language. Also, it uses CSS properties that are commonly used and easy to accidentally over-ride.

The Yahoo Accessibility Lab recommends using clip for content that should be hidden from the visual user, yet available to screen reader users. Thierry Koblentz has a great article on this technique, as well as the underlying philosophy behind using the correct CSS techniques for hiding content. Clip your hidden content for better accessibility

Steve Faulkner says:

thanks for the info Ted, will test and update the advice as appropriate!

position: absolute also prevents many popular JavaScript effects (jQuery, Prototype etc.) from working. At the time of this writing, JavaScript libraries heavily rely on display: none to create animations such as fadeIn(), fadeOut(), show(), hide(), slideUp(), slideDown(), animate() (and similar, in libraries other than jQuery). I think that many web developers will continue to use display: none also in the future. The point is that this declaration belongs to the screen media, not the speech one. If a screen reader interprets a declaration which has nothing to do with its media, this cannot be set as a rule to avoid this declaration.

George Walters says:

Another option is to use text-indent to hide the text if you don’t want users to see it. Zeldman had an article on this in early March, but the summation is code like the following:


.hide-text {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}

I’ve found it useful in most situations, especially when dealing with i18n and the rtl readers.

Steve Faulkner says:

Hi Gabriele,
I am missing your point, what exactly are you objecting to?

In my view, you create some false impressions:

FIRSTLY: Regarding @aria-hidden=false, the test result table indicates that test 5 and 6 Fail in all browsers. But, in reality, it is NOT a Fail – but a Pass, since it works as intended. That some might have an incorrect impression of how it is supposed to work, is a separate issue.

SECONDLY: You claim that @hiddden works in all browses. But actually – like you also admits – it requires display:none, to work in IE. This has implications for how you portray @aria-hidden=true, see below.

THIRDLY: What you say about @hidden, casts doubs about @aria-hidden=true. Fact is that, as long as the author adds display:none, then @aria-hidden=true works just as well as @hidden. And, fact is also, that ARIA RECOMMENDS to @aria-hidden=true with display:none: [aria-hidden=true]{display:none}

FOURTHLY: For the use case that something should ONLY be hidden for screen readers, then @aria-hidden=true is the only option. However, you fail to make any positive remarks about this advantage …

So — it seems like you are a little bit too eager to portray @aria-hidden negatively. ;-D

Steve Faulkner says:

Hi Leif,

So — it seems like you are a little bit too eager to portray @aria-hidden negatively.

I am eager to find the most robust method of hiding content from users. aria-hidden has no advantages over HTML5 hidden for this task. So why promote its use.

FIRSTLY: Regarding @aria-hidden=false, the test result table indicates that test 5 and 6 Fail in all browsers. But, in reality, it is NOT a Fail – but a Pass, since it works as intended. That some might have an incorrect impression of how it is supposed to work, is a separate issue.

What I am attempting to do there is drive home the the incorrectness of the impression that some developers appear to have i.e. aria-hidden=false actually does something.

SECONDLY: You claim that @hiddden works in all browses. But actually – like you also admits – it requires display:none, to work in IE. This has implications for how you portray @aria-hidden=true, see below.

Hidden is supported by current versions of Firefox, Chrome, Opera and Safari on multiple platforms. As noted IE 9 does not support hidden, it has been reported that IE 10 does.

THIRDLY: What you say about @hidden, casts doubs about @aria-hidden=true. Fact is that, as long as the author adds display:none, then @aria-hidden=true works just as well as @hidden. And, fact is also, that ARIA RECOMMENDS to @aria-hidden=true with display:none: [aria-hidden=true]{display:none}

HTML5 hidden is simpler and when fully implemented will not require authors adding a CSS style, the same cannot be said for aria-hidden, so there is no advantage to using aria-hidden for the use cases outlined.

FOURTHLY: For the use case that something should ONLY be hidden for screen readers, then @aria-hidden=true is the only option. However, you fail to make any positive remarks about this advantage …

It’s a rare use case, the much more common uses cases are the subject matter for this article.

In Drupal 7 and 8 development we have struggled with this same question. We ended up with a combination of the Clip technique along with the width:1px, height:1px.

Here is a blog post about our thought process: https://adaptivethemes.com/using-css-clip-as-an-accessible-method-of-hiding-content

Other resources:
https://snook.ca/archives/html_and_css/hiding-content-for-accessibility
https://webaim.org/techniques/css/invisiblecontent/

This brings up a quick question, where it states
“Use of HTML5 hidden (+ CSS display:none) worked in all screen reader/browser combinations tested.”

 Is there any reason why display:none couldn’t be used by itself to accomplish the same result?

The instructions imply that, only through a combination of both HTML5 and CSS, can content be properly hidden in a cross-browser compatible manner, but I’ve never heard of a circumstance where display:none fails to hide content appropriately. If there is, it would be great to know.

Plus, for dynamic applications, if you want to make a previously hidden element visible, you would have to change both the CSS and remove the ‘hidden’ attribute from the tag, otherwise content may be hidden for some and not for others.

Also, just as an FYI, when in Forms Mode in JAWS (such as when Auto Forms Mode is off), the following is announced every time you tab to another form field in the Comments form:
“how to remove CSS outlines in an accessible manner? HTML5 Accessibility Chops: hidden and aria-hidden Posted on May 1, 2012 by Steve Faulkner As a developer and also a consultant advising developers on how to develop accessible content, it is important”
At least using JAWS12 and IE8. This appears to result from the use of role=main within one of the parent tags. Removing this from the DOM fixes the problem.

Sincerely,
Bryan Garaventa

Steve Faulkner says:

Hy Bryan,

Is there any reason why display:none couldn’t be used by itself to accomplish the same result?

As indicated in the testing results display:none on its own works in all browser/AT combinations tested.

The reason for using an attribute in the DOM to provide provide a semantic indicator of state is detailed in the ARIA spec:

Some assistive technologies access WAI-ARIA information directly through the DOM and not through platform accessibility supported by the browser.

Same goes for HTML information in general. Use of display:none in isolation does not provide such an indication.

Plus, for dynamic applications, if you want to make a previously hidden element visible, you would have to change both the CSS and remove the ‘hidden’ attribute from the tag, otherwise content may be hidden for some and not for others.
For browsers that support the hidden attribute, adding it applies the CSS display:none automatically (content is not visible to any user) and removing it makes content visible to any user. If only hidden is removed the content will still be hidden for all users as the CSS rule will still be in place. If only the CSS rule is removed then the content will be available to IE users, but hidden for users of other browsers. That would result in a general authoring bug, not a specific accessibility bug and should be picked up by an developer worth their salt as the page will not work as expected in IE.
Also, just as an FYI, when in Forms Mode in JAWS (such as when Auto Forms Mode is off), the following is announced every time you tab to another form field in the Comments form:
“how to remove CSS outlines in an accessible manner? HTML5 Accessibility Chops: hidden and aria-hidden Posted on May 1, 2012 by Steve Faulkner As a developer and also a consultant advising developers on how to develop accessible content, it is important”
At least using JAWS12 and IE8. This appears to result from the use of role=main within one of the parent tags. Removing this from the DOM fixes the problem.

Thanks for pointing this out, I will attempt to fix it. JAWS has some bugs in regards to landmark roles.

Steve Faulkner says:

Hi Brandon, thanks for the info!

Steve Faulkner says:

Hi Bryan, think the issue is fixed now, added a role=form landmark to the from element.

Excellent, that does fix the form field tabbing issue 🙂

I understand what you mean about the HTML5 spec, but how does this fit in with proper XHTML syntax? For example, to validate properly, it would need to be written as hidden=”hidden”. Would this break the functionality if proper standards are observed?

Steve Faulkner says:

Hi Bryan,

I understand what you mean about the HTML5 spec, but how does this fit in with proper XHTML syntax? For example, to validate properly, it would need to be written as hidden=”hidden”. Would this break the functionality if proper standards are observed?

The only thing that breaks if hidden is used with a non HTML5 doctype is the HTML validator (in that it emits validation errors). Browsers do not care what DOCTYPE an author uses as long as the DOCTYPE does not trigger quirks mode. For example I have created a test page with the XHTML strict doctype, it contains a single P element with a hidden attribute. It works as expected in supporting browsers, but use of hidden is shown as an error when validated.

David Ward says:

I really Agree with 4th Point; I think ARIA is fantastic. I was working on a PhoneGap app an needed iOS Safari VO not to read a component EXPRESSLY for visual effects but doesn’t need read for those using VO. An I’m sure there’s some crazy reason you use the display:none stuff an what not but I don’t know what it would be..

Oh wait!! I didn’t even use aria-hidden junk in mine I went back an noticed I used role="presentation" … which did the same thing.. Maybe worth mentioning. I’m sure I tried the other but I must have fun into some probelms using it. Can’t remember what exactly.

Steve Faulkner says:

Hi David,
First off I am a proponent of WAI-ARIA when useful.

I used role=”presentation” … which did the same thing.

role=presentation is different, it will remove the semanics of an element, but not the text content.
Example:

heading


Will result in the heading and its content being hidden from users of supporting browsers and AT.

heading


Will result the text “heading” still being available, but the heading semantic “H1” will be removed from the accessibility tree.

Sarah Bourne says:

In the interest of completeness: there is one way to hide content from any user, which should be used if the content is never intended to be unhidden: the HTML comment. (Because nothing goes with out saying!)

David Ward says:

Thanks Steve, Good to know. I”m trying to make my app as cross platform on iOS as possible before I move over to something more like Android etc. Found iOS 4.3.5 doesn’t support near the feature set that 5.1 does when it comes to ARIA. I’m an adhoc dev and I’m learning slowly all the lingo.

Hi George,

That technique is not that safe. See: Replacing the -9999px hack