4

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>
TylerH
  • 20,799
  • 66
  • 75
  • 101
GentlemanHal
  • 154
  • 2
  • 8
  • that is the correct way to do it, however we normally add `tabindex="-1"` to the main container (`id="root"`) when we do it. Try adding that manually and running Axe then, I would imagine the problem will go away. If that works then I will add an answer – GrahamTheDev Jul 01 '20 at 14:05
  • Setting the `tabindex="-1"` on the `root` element made no difference, the warning is still generated. – GentlemanHal Jul 01 '20 at 16:21
  • I think that it is a bug then, however we don't get that problem at our side (but our stuff is all custom, could be hundreds of things that react is doing that could cause issues). I will try and put a test together and check it first, however in principle you are doing things correctly as I said earlier. – GrahamTheDev Jul 01 '20 at 18:25

3 Answers3

6

Short Answer

Adding aria-modal to your modal will remove this warning.

Long Answer

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!).

Hiding items outside a modal

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.

inert - a further string to your bow?

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.)

Example

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>
GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64
  • Thanks for this awesome and detailed answer, sadly I still get the same error on both my application and your example :-S I'm using the Chrome aXe plugin v4.5.3 (axe-core 3.5.5) – GentlemanHal Jul 02 '20 at 09:32
  • I am using the same? I also ran the page through the Axe CLI and got no error? The above is 100% the right way to do it so I think it may be a bug (possibly you have something setup differently, but I can't think what!) Sorry I am out of ideas how to get rid of the error, but just do it as above and you will be golden! Just double check that you defo didn't accidentally run the plugin on the wrong page (I know, but easy to do) as the above works on same setup! – GrahamTheDev Jul 02 '20 at 19:04
  • 1
    Didn't work for me with Angular Material dialog (which already had this attribute). But it looks like there is an open bug for this issue: https://github.com/dequelabs/axe-core/issues/3359 – Roobot May 26 '22 at 17:02
0

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.

Adam
  • 17,838
  • 32
  • 54
-1

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/

swadhera
  • 30
  • 2
  • From the same page "It is important for users of screenreaders that other page content be hidden (via the aria-hidden attribute) while the modal is open." and "If you are already applying the aria-hidden attribute to your app content through other means, you can pass the ariaHideApp={false}". So it seems like your suggestion would remove the warning and replace it with a real accessibility issue... – GentlemanHal Jul 01 '20 at 16:17