Axe-core: <ul role="menubar"> not recognizing <li><a role="menuitem"></a></li> as a descendent

Created on 2 Oct 2018  路  16Comments  路  Source: dequelabs/axe-core

In the version 3.5 chrome extension update from 9/25/18, a menu structure like the following:

\

Throws the following flag:

\
  • elements must be contained in a \
      or \
    • This is inconsistent with the specs layed out here: https://www.w3.org/TR/wai-aria-practices/examples/menubar/menubar-1/menubar-1.html

      If the menuitem role is moved to the list item, the flag goes away.

      It appears as though the AXE algorithm is only looking for Direct Decedents to have the role of menuitem, instead of any descendent of the parent menubar.

      https://www.w3.org/WAI/PF/aria/roles#menuitem states that "Authors MUST ensure that menu items are owned by an element with role menu or menubar in order to identify that they are related widgets. Authors MAY separate menu items into sets by use of a separator or an element with an equivalent role from the native markup language."

      and an owned element is defined as "any DOM descendant of the element, any element specified as a child via aria-owns, or any DOM descendant of the owned child." here: https://www.w3.org/WAI/PF/aria/terms#def_owned_element

      Issue can be seen here: https://templatelibrary.schoolwires.net/academy

      I am a web developer for Blackboard, Inc. and we have hundreds of sites out there that are now getting this flag. Thank you for looking into it!

      accessibility support rules

      Most helpful comment

      I ran into this same issue with different roles, so I thought I would mention it here to be safe and not create clutter with another ticket.
      <ul role="tablist"><li><a role="tab">Blah</a></li></ul>

      The tab accessibility (https://www.w3.org/TR/wai-aria-1.1/#tab, "Authors MUST ensure elements with role tab are contained in, or owned by, an element with the role tablist.") indicates that should be valid.

      In particular, it's used by a fairly popular bootstrap/angular component library called ng-bootstrap (https://ng-bootstrap.github.io/#/components/tabset/examples).

      Thanks!

      All 16 comments

      Thanks for reporting. I'm quite surprised that this seems to work. I've seen different cases where, unless there is a role=presentation or role=none on the element between the owner and the owned element, the screen reader can't work out how many items are in that group. Testing the example in VoiceOver gets me a correct count, so it seems something more is going on there. Have you tried testing this in NVDA or JAWS? Do they give you a correct count of menu items?

      @WilcoFiers I don't have access to NVDA or JAWS, so I'm not sure... but I have seen what you mentioned in VoiceOver.

      Update: I've done a bunch of research. There is quite a bit going on that I wasn't aware of. I'm working to reverse engineer the algorithms used to come up with this list of owned elements, so that axe can correctly identify what elements belong where. It'll take some time to get this done, but it's high on my priorities list.

      @bbAdam After further testing we discovered that there are issues with this pattern. Most notably NVDA + Firefox does not support this method. Because of the orphan list items, each menu item is counted as a list of 1. An issue has been filed with the ARIA working group to fix the example.

      We are going to look at how we can better expose this information through axe-core, so for that purpose I'm keeping this issue open. I'm removing the "bug" label from it though, as this technique not working in Firefox means it doesn't meet the baseline for accessibility support in axe.

      I ran into this same issue with different roles, so I thought I would mention it here to be safe and not create clutter with another ticket.
      <ul role="tablist"><li><a role="tab">Blah</a></li></ul>

      The tab accessibility (https://www.w3.org/TR/wai-aria-1.1/#tab, "Authors MUST ensure elements with role tab are contained in, or owned by, an element with the role tablist.") indicates that should be valid.

      In particular, it's used by a fairly popular bootstrap/angular component library called ng-bootstrap (https://ng-bootstrap.github.io/#/components/tabset/examples).

      Thanks!

      I am seeing the same violation as @smithk58 above. It looks like axe flags this whenever the wrapping <ul> has any role other than role='list'

      I'm having the same issue with role='group' and role='radiogroup'. I have something like:

      <div id="question">Question</div>
      <ul role="radiogroup" aria-labelledby="question">
      <li><label><input type="radio" id="one" name="one" /> One</label></li>
      <li><label><input type="radio" id="two" name="two" /> Two</label></li>
      <li><label><input type="radio" id="three" name="three" /> Three</label></li>
      </ul>
      
      <li> elements must be contained in a <ul> or <ol>
      
      
      
      md5-5eee1a9137dda1b95ccf09e38e36d250
      
      
      
      Radio inputs with the same name attribute value must be part of a group
      

      @lukescott put role=presentation on all interim structures to remove their semantics or else you will get bad behavior in assistive technologies

      @WilcoFiers I think we should close this as it works correctly

      @dylanb - I have to disagree assuming this project intends to conform to the w3c standards. I linked directly to an example of them saying what I posted should be valid. It's not even slightly ambiguous, as they link directly to their definition of "owned" where it says any descendant.

      If the project doesn't want to conform to the standards fully that's definitely not up to me to decide (I understand it's not simple), but I thought I should emphasize that since you might not have visited the link.

      Thanks!

      @smithk58 Apologies, I never saw that response. There is no good definition in any W3C specification about owned elements at the moment. Browser are inconsistent about this, which is why I would not recommend doing anything other than a direct parent-child relationship. It is not cross-browser compatible.

      There is an issue open for this on the ARIA spec, it's tagged for WAI-ARIA 1.2, so hopefully this can be resolved at some point. https://github.com/w3c/aria/issues/1033

      It seems that the issue is that the <li> is not supported without a role=presentation or role=none. The https://www.w3.org/TR/wai-aria-practices/examples/menubar/menubar-1/menubar-1.html# example uses role=none as it should as any <li> needs to be contained inside of a <ul> or <ol> without an overriding role. In all these examples given, the <ul>s role has been overridden so axe correctly flags this as a problem as @stevemchey correctly noted.

      The problem is not that the different roles of menuitem, tab or radio are not contained inside of their appropriate require parent roles of menu, tablist, or radiogroup, as axe is not flagging that as the issue.

      I believe that the fix is to update the error message to include that the <ul> and <ol> need to not have a role.

      <li> elements must be contained in a <ul> or <ol> without a role or an element with role="list".
      

      @WilcoFiers - No worries, thanks for responding!

      I might be overlooking something, but isn't w3 the source for defining them (I could be super wrong about that)? If so, they so have a definition of owned: https://www.w3.org/TR/wai-aria-1.1/#dfn-owned-element. My apologies if I'm wrong or overlooking something and wasting your time though.

      Either way, if browsers aren't following that consistently I could see how that makes copying it a bad choice, even if it's closer to the spec.

      I think there are subtle but important differences between putting a group role and a presentation role on a <ul> element.

      The ARIA 1.1 entry for the presentation/none role specifically states that it will remove the semantics from the element itself as well as its required owned elements.
      When applied to a <ul> element it will nullify that element as well as any <li> element descendant (because a <li> element is a required owned element of a <ul> element).

      The spec does not say that when you repurpose an element with required owned elements using the role attribute that its required owned elements are automatically changed or their implicit semantics should be removed.

      so

      <ul role="none">
      <li>item 1</li>
      <li>item 2</li>
      </ul>
      

      should be flattened to a bunch of divs, and this is pretty well supported across browsers and a.t.

      but

      <ul role="tablist">
      <li> <a href="#" role="tab" aria-selected="true">item 1</a> </li>
      <li><a role="tab">item 2</a> </li>
      </ul>
      

      is different.
      The <ul> container element has been repurposed as a tablist, which can only own elements with role="tab". In this case, since there is no ARIA direction that the required owned elements <li> should be turned into divs this construct violates that ARIA rule.
      I don't think the ARIA spec should have that requirement, you could just turn the <li> elements into tabs directly by adding role="tab" and the expected functionality.
      Maybe it could have the requirement that required owned elements that do not have the required owned elements role for a grouping element role should be turned into divs. That would require a lot of work by browser and a.t. vendors to reinterpret that, and I think it's the authors responsibility in this case, the author could just have started with divs and spans or use the presentation role to manually remove superfluous semantics.

      Here , after all of the above suggessions tried, I observed,

       <ul role="menu"> or  <ul role="menubar"> (not ul role="menuitem" ) no such above mentioned error seeing (<li> elements must be contained in a <ul> or <ol> ).
      

      Which is actual behaviour of <ul> I think. @straker what else I need to QAed here ,. and is this what we are expecting?

      @padmavemulapati Please reach out to the developer once again and close this ticket asap.

      <ul> or <ol> 
      

      parent element do not have an overriding role, so is passing and the remianing roles failing (even )

      Was this page helpful?
      0 / 5 - 0 ratings