3

I have a simple chunk of code that I'm trying to make keyboard accessible while using the NVDA screen reader.

Specifically, I have a div with a role of "button", with another div with another role of "button" nested inside it. Each div has a different onkeydown event that gets fired when the user tabs to that div, and presses "enter".

This keyboard functionality all works as desired when I don't have the NVDA screen reader turned on.

When I do have the screen reader turned on, however, the nested keydown event no longer fires. Instead, just the parent event fires even when the nested event is one that has focus.

However, if I manually change NVDA out of "browse mode" and into "focus mode" (By pressing the NVDA key + spacebar), then the key events work as desired again.

Unfortunately, it's not acceptable for me to expect someone using NVDA to know to make the manual switch to "focus mode". It either needs to change to "focus mode" automatically, or it needs to work in "browse mode."

Here's the code:

HTML:

<div role="button" 
   tabindex="1" 
   onkeydown="keyEvent(event, outerDivAction)"
   class="outerDiv">
   Outer Div

   <div role="button" 
     tabindex="1"
     onkeydown="keyEvent(event, innerDivAction)"
     class="innderDiv">
     Inner Div</div>
   </div>

<div class="result"></div>

JavaScript:

function outerDivAction(event) {
  event.stopPropagation();
  console.log('outer div');
   $('.result').html('<p>outer div!</p>');
}

function innerDivAction(event) {
  event.stopPropagation();
  console.log('inner div')
  $('.result').html('<p>inner div!</p>');
}

function keyEvent(event, callback) {
  event.stopPropagation();
  if (event.which === 13) {
    callback(event);
  }
}

$('.outerDiv').click(outerDivAction);

$('.innderDiv').click(innerDivAction);

You can also view a codepen here: http://codepen.io/jennEDVT/pen/Yprova

Any help that anyone can offer would be greatly appreciated!

p.s. I know that if I take the nested div and move it so that it's no longer nested, but is rather a sibling of the first div, then everything works as desired. Unfortunately that's not an option. The div needs to be nested.

jennEDVT
  • 709
  • 9
  • 13

2 Answers2

6

This is not a bug in NVDA.

First of all, you cannot have nested clickable elements. Specifically, you cannot have nested interactive content. You cannot nest links and you cannot nest buttons. You cannot nest links in buttons, and you cannot nest buttons in links. There are other kinds of interactive content worth looking into for future reference too.

You may find that your code is technically valid, but that is only because what you have written is a fib.

Instead of using the correct element (<button>) you have chosen to put role=button on <div>s. An HTML validator would pass your code because it is valid to nest <div>.

However, by giving them each role=button, you have instructed the user agent to treat them as <button> (minus all the benefits that come with them, like accessibility, key handlers, semantics, etc.).

Now let's go back and validate that code again as a user agent would see it (as nested <button>s). The W3C Nu HTML checker would fail it (I know because I ran a test):

Error: Start tag button seen but an element of the same type was already open.

My suggestion is:

  • to not nest them,
  • convert them to <button>s,
  • remove the invalid tabindex=1 (which you would not need),
  • remove the check for the key code as the <button> gives you that for free (including character 32),
  • make your <div class="result"> into an ARIA live region (there are some tips here),
  • and put a wrapper around the buttons to give you the visual effect you want.

Sample rejiggered code:

 <div class="wrapper">
   <button class="outerDiv">
     Outer Div
   </button>
   <button class="innderDiv">
     Inner Div
   </button>
 </div>

 <div class="result" role="alert" aria-live="assertive"></div>
Community
  • 1
  • 1
aardrian
  • 8,581
  • 30
  • 40
  • Thanks for taking the time to provide such a comprehensive explanation. Unfortunately, this will be difficult to implement since the actual spec I'm developing to is a navigation with some items that have dropdown menus associated with them, and then the dropdown items have an additional submenu displayed as a flyout menu. And each of those items can sometimes be buttons (that open a submenu) or links, and so currently I use JavaScript to dynamically change them from role="button" to role="link". The reason the elements are nested is because the submenus are children of the parent items. – jennEDVT Nov 30 '16 at 13:51
  • To avoid nesting buttons, could you restructure your code to use a list with nested sublists(that contain buttons)? It takes a bit more effort to control the visibility based on the focus of the list items (or button toggle), but it avoids the nested interactive content that @aardrian mentioned. Here's a codepen to illustrate what I mean: http://codepen.io/anon/pen/KNyZYm – Skerrvy Nov 30 '16 at 14:09
  • @jennEDVT, you may have little choice but to refactor as you will always run into issues with assistive technology. Skerrvy has a good quick demo of what you can try. Also, look for existing patterns that you can modify. For example, Adobe has a complex mega menu that, while too much for most sites, may be a fit? http://adobe-accessibility.github.io/Accessible-Mega-Menu/ – aardrian Nov 30 '16 at 14:39
  • Thanks for all the suggestions, as well as resources to look into. It sounds like a refactor is in order. – jennEDVT Nov 30 '16 at 16:19
1

If it may interest you, the WAI-ARIA Authoring Practices (APG) has guidance on how to make various design patterns accessible. It also includes one on what you’re describing: Menu or menubar which includes code examples for menus with submenus.

Zoë Bijl
  • 11
  • 2
  • Please edit some code that would help the OP into your answer. Link-only answers (meaning any answer where the solution itself is presented as a link and not explained in the post itself, even if other, non-link text is present) are generally frowned on, because they can be invalidated if the link goes down, and have been used in the past for self-promotion. – Justin Time - Reinstate Monica Dec 01 '16 at 00:24
  • Thanks for the resources! – jennEDVT Dec 02 '16 at 14:01