Search code examples
accessibilitywai-ariascreen-readers

aria role="application" and tab-trapping


Tab trapping is a fairly well established pattern (example). Typically for the sake of accessibility, it allows keyboard users to navigate inside dropdown menus and modals. What's concerning however are the implications for users now that the native functionality of the tab event has been overwritten with a new behavior (looping). This isn't a big deal for sighted users, but it is problematic for users of Assistive Technologies like NVDA and JAWS that critically rely on that native tab functionality.

WAI-ARIA has a solution for informing Assistive Technologies of when native keyboard functionality has been overwritten in the form of aria-role="application":

Keyboard interaction is completely under the web author's control and can be anything associated with the particular widget being implemented. In a slides application, for example, a widget could be created that uses the arrow keys to position elements on the slide, and uses audio feedback via an ARIA live region to communicate the position and overlap status with other objects. Focus is being managed via aria-activedescendant.

The tab , Space and Enter keys, as well as Escape , must be handled by the application. The one exception is if focus is set to a standard widget inside the application that supports keyboard navigation from the browser, for example an input element.

This would imply that any component that employs tab-trapping should necessary have a role="application", always.

However I don't believe this common practice. Sites like Target.com for example (that use tab trapping on their dropdown menu) categorize it as a list, as seen here in the website Accessibility Tree: enter image description here

I'd appreciate any experienced perspectives on this. Am I interpreting ARIA correctly here? Should components that employ tab-trapping always be decorated with role="application"?


Solution

  • Short Answer

    You do not need to add role="application" provided you set the menus up as modal dialogs. With other patterns it may be applicable (highly unlikely, role="application" is a very specialised role) but at that point you probably implemented the wrong pattern in the first place.

    Longer Answer

    The loop pattern is fine as long as implemented correctly (and target.com did a pretty good job)

    There is nothing wrong with this pattern as long as it is implemented correctly (which target.com seems to surprisingly do a quite good job of, just a few things they could do better).

    Using 'target' as an example, you will notice that when you click on 'categories' for example the revealed menu actually gets treated like a modal dialog.

    It has role="dialog" and the 'button' that opens it has aria-expanded.

    They also trap tab focus within this modal and provide a 'close' button that appears at the bottom of the list if you are using the tab key.

    All good so far, nothing wrong with looping within a modal dialog as that is expected behaviour.

    They also get a few other things right, once the 'dialog' is open you cannot access any other content. For example in a screen reader you may press the keys 1-6 to find the next heading levels, you cannot do this while the menu is open as they apply aria-hidden="true" to everything outside of the menu modal (a true modal trap).

    Also you can close the menu modal and focus is returned to the menu item that opened it in the first place, so they manage focus correctly too.

    Finally you can close the menu modal with the Escape key, which is also expected behaviour.

    So if you wanted to follow this pattern for your menus I would say go for it, they are accessible as they are and a screen reader user would not struggle using them.

    What can we do better than target.com

    Target got the basics right, they are just missing a few key steps.

    The 'button' that opens the menu should have the aria-controls attribute just to link that together properly.

    The menu items within the menu dialogs should all have <nav> elements around the <ul> (although arguably as these modals should only be accessible via the menu button this association is implied and this is a minor point).

    The arrow sprites they use have focusable="false" which is good but they didn't add role="presentation" or better yet aria-hidden="true" so they do get announced if your screen reader is set to verbose. (aria-hidden="true" is preferable as support is better).

    The menus themselves should not really be multi-layered. i.e. if you click 'main menu' at the top of the list it then becomes confusing as to where you are, am I still within the modal dialog? Additionally this is implemented in a way where it does not announce the first item in the 'main menu' list once you follow the link (timing issue maybe?) so it is disorientating. This is the biggest problem with their implementation.

    There are other things but you get the idea, if your menu is just a single list per 'drop down' (modal), the way this is implemented is perfectly acceptable and usable and better than a lot of menu implementations I have seen.

    So should I use role="application"

    No.

    Seriously, you will probably never need to use this during your career and it's use can break a lot of accessibility.

    Oh you want more detail? No problem!

    No you do not need to use role="application" here, in fact you would introduce a lot more accessibility issues doing so.

    role="application" implies that all the controls are custom and that you should disregard the standard website controls. (you are basically telling the user / screen reader 'treat this like a desktop application where shortcut keys will be explained via the menus etc.' and 'expect some strange behaviour that is not associated with websites, do not rely on your normal keyboard shortcuts as they probably won't work')

    As this follows a standard web pattern (trapping focus within a modal) adding role="application" would actually confuse people.

    You mentioned about the Tab looping, but within the list it functions as expected (pressing the down arrow at the end of the list does not loop) so the Tab looping only occurs within the modal.

    I think the following quote for the page I linked on role="application" summarises the important information. I have added bold for emphasis on the key points that are applicable to your question and added comments after if appropriate.

    The application role indicates to assistive technologies that this part of the web content contains elements that do not conform to any other known HTML element or WAI-ARIA widget. Any sort of special interpretation of HTML structures and widgets should be suspended, and control should be completely handed over to the browser and web application to handle mouse, keyboard, or touch interaction.

    In this mode, the web author is completely responsible for handling any and all keyboard input, focus management, and other interactions and cannot assume assistive technologies would do any processing on their end.

    So basically if you added role="application" you would then not get the native behaviour of any element, this would introduce a lot of work! (in practice most screen readers will still allow basic functionality, but they do this because people misuse role="application")

    If the web application encompassed by the application role contains parts that should be treated like normal web content, a role of document or article should be used.

    So you would have to add role="article" or role="document" to the lists, the close buttons etc. Basically the whole thing would have role="article" anyway (as that would be the most appropriate role).

    Unless you are building very complex software, role="application" should not be used.