Reputation: 354
I'm using React Modal in my application and when it is open running the aXe accessibility tool gives the following error:
aria-hidden elements do not contain focusable elements
This is because the React modal adds a aria-hidden="true"
to the root element of the application (the div all my apps components are rendered under, but not the modal), but it does not update the tab index or disable every focusable element.
However the React modal traps the keyboard focus, so the user can't tab out of the modal and clicking the background closes the modal.
So my question is:
Is this actually an issue I need to fix? Or is this a false positive as the tool doesn't have knowledge of the modal trapping focus?
If this does need to be fixed, is my only option to manually update the tab index or disable every focusable element?
The HTML when the modal is open looks kinda like this:
<div data-react-modal-body-trap="" tabindex="0" style="position: absolute; opacity: 0;"></div>
<div id="root" aria-hidden="true">application content</div>
<div class="ReactModalPortal">
<div class="ReactModal__Overlay ReactModal__Overlay--after-open modal-overlay-6fODnA">
<div tabindex="-1" role="dialog">modal content</div>
</div>
</div>
Upvotes: 14
Views: 65092
Reputation: 11
Need put tabindex="-1" into for each input or / and button that you have. And in your modal add the next:
Add aria-hidden and tabindex should fuctionUpvotes: 1
Reputation: 24905
Adding aria-modal
to your modal will remove this warning.
It took me a while to realise why our modals do not have this warning but yours would as we employ similar markup. We use the aria-modal
property on our modals.
Axe has been updated to expect the aria-modal
property on a modal. aria-modal
has average support at the moment but it is a good practice as it counters developer mistakes (as screen reader / browser combos that do respect it will automatically trap focus for you!).
The only way to truly hide everything is to add tabindex="-1"
to every single interactive item.
However in reality that is far more likely to cause a catastrophic accessibility issue if your JS function you use to add tabindex="-1"
to every interactive element encounters an issue and doesn't successfully revert the tabindex
or remove it. This would mean you leave parts of the page completely inaccessible!
Obviously you would then fail WCAG on the "Robust" part of POUR. Please don't do this.
The best compromise is to use aria-hidden
on the <main>
and <aside>
containers (any top level containers). Then use aria-modal
on your modal as this will trap focus in some browser / screen reader combos. That combination of aria
will provide the highest coverage for browser support.
Finally you should manage focus for people using the tab
key. This is our backup in case the above methods fail and for people not using a screen reader (i.e. people with dexterity or accuracy issues who can't use a mouse.)
If you need information on how to trap the tab focus within a modal I will provide a code sample but it is pretty straight forward.
Managing tab key focus will not stop screen reader users or misbehaving plugins from getting outside your modal (if the other methods fail) but believe me, if they have a problem with your site after you implement the above they will have bigger problems on other sites.
Finally as another backup we add inert
to the items outside of our modal. Support isn't great, but every little helps!
You can polyfill it if you want but I don't think it has moved outside of the draft spec yet so we just use it as is.
It is purely there as yet another add in and (hopefully) to future proof our legacy applications as inert
is a much needed and easy to understand attribute. It blocks screen readers access to items without changing visual design (basically aria-hidden
but as a standard attribute, with the advantage that it effectively removes all children from the accessibility tree.)
Try removing the aria-modal="true"
from the following example and running Axe, the warning will return.
<main aria-hidden="true" inert><a href="https://google.com">test</a></main>
<div class="modal" aria-hidden="false" aria-modal="true">
<label for="iTest">input test</label>
<input id="iTest"/>
</div>
Upvotes: 22
Reputation: 18855
Is this actually an issue I need to fix? Or is this a false positive as the tool doesn't have knowledge of the modal trapping focus?
A plugin listing all links in the page will still list the links if they are not disabled (by removing the tabindex for instance).
When dealing with accessibility you have to always consider that custom plugins not relying on ARIA can or will exist.
ARIA is mainly used by screenreaders : it's not a requisit for assistive technologies but an overlay for them to improve accessibility.
For instance, an eye tracking device may also trigger the first clickable element at a given position, and as the overlay of your plugin is not in the tab order it might activate an element behind.
And third consideration : some paywall bypass protection, or anti-ads plugins may automatically remove overlays.
Upvotes: 0
Reputation: 30
you get the warning , as when the aria-hidden="true"
is set to root element , your page might have focussable elements, which is against this rule.
thus to avoid this you can always set ariaHideApp={false}
in your Modal which will not set the aria-hidden="true"
and you will still have your focus trapped with in the opened Modal.
http://reactcommunity.org/react-modal/accessibility/
Upvotes: -1