![](http://habrastorage.org/getpro/habr/avatars/902/c7a/49b/902c7a49be188965de879f924b676efc.jpg)
It's a (focus) Trap
People who write standards are very cleverly settled. It is enough for them to write how everything should work well, and then their problems are no longer.
This is exactly what happened with the “how dialogs should work”, or rather, the “correct” modal dialogs from the point of view of a11y.
In the description of the dialog role on MDN, everything is written very simply:
The problem is that MDN forgot one more important point, and all the others forgot about one of the above - that the modal should not let the trick out of its hands. The active element must be locked. Do not let him escape from our trap.
![](https://habrastorage.org/web/024/a8b/837/024a8b837d134f8ca9103d4649181657.jpeg)
The story began just recently - in the Web Standards Newsletter I got a link to the “correct” WAI-ARIA Dialog . And away we go.
The component is actually good:
He does everything that he asks for MDN and even more, since without the first item “exit” from the dialogue with the activated screen reader is not difficult.
In general - must have!
![](https://habrastorage.org/web/452/bc6/aae/452bc6aaea954db3aa0a959e239076e2.gif)
But the implementation of " focus-management " was a little disappointing - the guys really intercept keyboard events (and not only) and emulate the tab button themselves.
It’s so incomprehensible that I decided to dig a little how “this” should work in general. The word "dig" means to check how various sites and frameworks deal with tabs.
Let's start with the sites (a bit biased selection):
The conclusion is simple - the “normal” sites have a little lack of brains, and Yandex tear off their hands.
With frameworks (a slightly biased selection) is much more interesting:
With frameworks, it is also quite bad. And absolutely no one hangs aria-hidden on the rest of the content to make the modal actually accessible to people who are forced to use screen readers.
In fact, I also didn’t bother with all this garbage before, but here, as an evil, my dear wife decided to learn HTML HTML page layout where pepelsbey with a big, big company made her and me think about how tabable my site is.
I had to learn new science and solve the problem with focus.
In general, as they said on Leo Tolstoy Street ... - and what are your suggestions .
In fact, the problem is very simple - despite the fact that millions of modules have been written for JS, there are practically no modules for focus management.
In general, 7 troubles = +1 new bike . Or rather, a real train from focus-lock , dom-focus-lock , react-focus-lock and vue-focus-lock - for all occasions.
From the side of the wrapper (react, vue, dom), everything is very simple - get the DOM node and close the focus in it. All salt is in focus-lock.
There are several reasons for creating a new library:
So I had to make another bike, which temporarily meets a slightly larger list of whistles than its closest competitors. Or specifically everyone.
Just wrap the modals (and not only the modals) in FocusLock - and half of the problems will be solved by the
React-focus-lock demo - codesandbox.io/s/jvl0k6zyk3 ( find the difference ).
Vue-focus-lock demo - codesandbox.io/s/l5qlpxqvnq
But only half, since aria-hidden (or inert) will have to be hung up by someone else and somewhere else. But that's another story.
Total do not forget% username% that modals are not only a gray lightbox that does not click with the mouse, but also the wonderful world of keyboard exercises.
But most importantly - do not forget that you do not need to interfere with the user’s operation of the site not only with the mouse.
In general - don't fall for it - github.com/theKashey/react-focus-lock
This is exactly what happened with the “how dialogs should work”, or rather, the “correct” modal dialogs from the point of view of a11y.
In the description of the dialog role on MDN, everything is written very simply:
- The dialog must be properly labeled
- Keyboard focus must be managed correctly
The problem is that MDN forgot one more important point, and all the others forgot about one of the above - that the modal should not let the trick out of its hands. The active element must be locked. Do not let him escape from our trap.
![](https://habrastorage.org/web/024/a8b/837/024a8b837d134f8ca9103d4649181657.jpeg)
Modal dialog
The story began just recently - in the Web Standards Newsletter I got a link to the “correct” WAI-ARIA Dialog . And away we go.
The component is actually good:
- it hangs aria-hidden on the page to hide the content from screen-readers (only works in the first example).
- it obscures the content and cuts down the scroll of the page.
- controls focus, so that from the modal it is impossible to snag.
- after closing the dialog, it returns focus to the starting position.
- and adds different aria-specific tags, of course.
He does everything that he asks for MDN and even more, since without the first item “exit” from the dialogue with the activated screen reader is not difficult.
In general - must have!
![](https://habrastorage.org/web/452/bc6/aae/452bc6aaea954db3aa0a959e239076e2.gif)
Focus
But the implementation of " focus-management " was a little disappointing - the guys really intercept keyboard events (and not only) and emulate the tab button themselves.
It’s so incomprehensible that I decided to dig a little how “this” should work in general. The word "dig" means to check how various sites and frameworks deal with tabs.
Let's start with the sites (a bit biased selection):
- Google Gmail | G + - perfect. ️
- Classmates - with the departure of the tab, they close the modal, to which the focus never comes
- FB - depends on the page. In the group / on the personal page - there is nothing at the time of writing messages. Never press Tab (in safari) on the main - the roof blows.
- VK - page "randomly" ignores tab ️
- Yandex.Maps - the page completely ignores the tab ️
- Yandex.Music - the page completely ignores the tab ️
- YAN - no focus management.
- LiveJournal - no focus management.
- My own sites - no focus management.
- Habrahabr - no focus management, modals
- Jira / Confluence - perfect. ️
The conclusion is simple - the “normal” sites have a little lack of brains, and Yandex tear off their hands.
With frameworks (a slightly biased selection) is much more interesting:
- jQuery UI - by focusIn outside of the module hangs focus back in a certain order. There is a selector for tabbable and focusable. It works on parole, but good - github.com/jquery/jquery-ui/blob/master/ui/widgets/dialog.js#L300
- Ant.Design - actually uses rc-dialog for this case, which hangs the handler only on Tab. Via shift + tab you can exit back.
In general, this is the most crooked code of all presented here, even giving a link is unpleasant - github.com/react-component/dialog/blob/master/src/Dialog.tsx#L133 - BluePrint.js - VERY highly customizable Modal is able, including the enforceFocus property for this matter. One thing is bad - it works only for autoFocus fields, and fields with the specified tabIndex. What were they thinking? - github.com/palantir/blueprint/blob/master/packages/core/src/components/overlay/overlay.tsx#L312
- Bootstrap? Throws focus on himself. Shift + Tab rests against the beginning and gets stuck - github.com/twbs/bootstrap/blob/900da3e235305c2daefe86c0a960e36be6e1b60b/js/src/modal.js#L280
- AUI is the only framework that has a dedicated class for focus-manger and generally works “correctly” - according to focusOut and event.relatedTaget - bitbucket.org/atlassian/aui/src/92b8ce839ef1b6f320fe6a590def1cbc40cd2724/src/js/auiager
- Atlaskit, RamblerUI, MaterialUI and even the Semantic-UI (+ React version) - no hints of focus management.
With frameworks, it is also quite bad. And absolutely no one hangs aria-hidden on the rest of the content to make the modal actually accessible to people who are forced to use screen readers.
Offtopic
In fact, I also didn’t bother with all this garbage before, but here, as an evil, my dear wife decided to learn HTML HTML page layout where pepelsbey with a big, big company made her and me think about how tabable my site is.
I had to learn new science and solve the problem with focus.
PS: Vadim recommends scoring all this aria-hidden with focus-management and using the inert html attribute , which simply “turns off” (I’m completely lying) everything except the modal and there will be no problems with screen / reader or with focus.
Although I’m not sure about the second one, and it still doesn’t work very well, and the polyphiles are simply terrifying .....
Focus lock
In general, as they said on Leo Tolstoy Street ... - and what are your suggestions .
In fact, the problem is very simple - despite the fact that millions of modules have been written for JS, there are practically no modules for focus management.
- focus-manager is a simple focus-manager with a simple and vanilla API and a great example . There are a couple of cons
- ToleFocus is some kind of monster that you want to run away from.
- react-focus-trap is so simple that it returns focus only to the beginning.
- Focus manager from AUI, but who has heard of AUI before ?
- focus-trap , it is also focus-trap-react which was used in the WAI-ARIA demo at the beginning of the article. And which by default is turned off by Esc and generally does not use the DOM-API very correctly
In general, 7 troubles = +1 new bike . Or rather, a real train from focus-lock , dom-focus-lock , react-focus-lock and vue-focus-lock - for all occasions.
From the side of the wrapper (react, vue, dom), everything is very simple - get the DOM node and close the focus in it. All salt is in focus-lock.
There are several reasons for creating a new library:
- Unfortunately, all solutions (except for focus-trap / lock) completely ignore tabIndex and become completely inoperative if one smart programmer breaks the tabbing order.
The case, of course, is a little synthetic, but quite real. To my great regret. - Of all the solutions (except focus-trap / lock and react-focus-trap), you can easily tab up in safari (JFYI: safari distinguishes Tab and Opt + Tab). And if the focus once leaves the trap - no one will return it back.
- focus-trap, which works so well everywhere, does this because it intercepts and emulates the Tab, they completely ignore the settings of the same Safari paragraph above.
- All solutions (except focus-lock and BluePrint.js) select the first element at the input, not the autofocus element.
PS: focus-trap is looking for an element with the initialFocus attribute. Why?
So I had to make another bike, which temporarily meets a slightly larger list of whistles than its closest competitors. Or specifically everyone.
Just wrap the modals (and not only the modals) in FocusLock - and half of the problems will be solved by the
React-focus-lock demo - codesandbox.io/s/jvl0k6zyk3 ( find the difference ).
Vue-focus-lock demo - codesandbox.io/s/l5qlpxqvnq
any data
But only half, since aria-hidden (or inert) will have to be hung up by someone else and somewhere else. But that's another story.
Total
Total do not forget% username% that modals are not only a gray lightbox that does not click with the mouse, but also the wonderful world of keyboard exercises.
But most importantly - do not forget that you do not need to interfere with the user’s operation of the site not only with the mouse.
PS: Better yet, turn on VoiceOver or another ScreenReader and try your sites for strength. You will be surprised.
Many things, for example, “manual keyboard navigation” in Yandex.Mail, do not actually change the active element. Yandex definitely lost
one programmer from Finland as a user.
PPS: Gmail, however, is not that much better.
In general - don't fall for it - github.com/theKashey/react-focus-lock