We have some tabs on our page with the following structure:
<ul role="tablist">
<li>
<div role="tab" tabindex="0" aria-selected="true" aria-controls="id1">First tab content...</div>
</li>
<li>
<div role="tab">Second tab content...</div>
</li>
</ul>
This gives rise to two violations when running Axe accessibility tests, namely:
<li> elements must be contained in a <ul> or <ol>, and Certain ARIA roles must contain particular children (also the converse that certain children need particular parent roles).
I understand that the first violation is due to the tablist role meaning that the <ul> is no longer seen as a <ul>. I don't understand the second violation as the spec does not enforce that elements with role="tab" are immediate children of tablist.
One possible fix, which prevents these violations, would be to move role="tab" up to the <li> elements. The problem then though is a different violation: Nested interactive controls are not announced by screen readers, due to the contained <div> being focusable presumably. Changing this to the outer <li> would require a whole load of js and css changes, so is not a simple fix.
To what extent does this really need fixing and what is the best approach?
Axe is wrong. The spec for the tab role says:
Authors MUST ensure elements with role tab are contained in, or owned by, an element with the role tablist.
Emphasis mine. Notice that is says a tab must be contained in a tablist. Contained in does not mean a direct child but rather a descendent.
This is further emphasized if you look at the next phrase, or owned by. "Owned" has a definition:
An 'owned element' is any DOM descendant of the element, any element specified as a child via aria-owns, or any DOM descendant of the owned child.
So again, as long as the tab is a descendant of a tablist (child, grandchild, great-grandchild, etc), then technically it's valid and axe is wrong.
Now, the definition of "owned" gives you a clue as to how you can work around axe's bug in case the violation bothers you. Add aria-owns to your <ul> and point it to the tab elements (your <div>s). Your original code will pass axe like this:
<ul role="tablist" aria-owns="foo1 foo2">
<li>
<div id="foo1" role="tab" tabindex="0" aria-selected="true" aria-controls="id1">First tab content...</div>
</li>
<li>
<div id="foo2" role="tab">Second tab content...</div>
</li>
</ul>
You still have the issue of an <li> not contained in a <ul>. #graham covered that part. And I also agree with #graham that you should follow the authoring practice for the tab design pattern.
The answer with your current setup is to remove the semantic meaning from the <li>.
<ul role="tablist">
<li role="none presentation">
<div role="tab" tabindex="0" aria-selected="true" aria-controls="id1">First tab content...</div>
</li>
<li role="none presentation">
<div role="tab">Second tab content...</div>
</li>
</ul>
role="none presentation" removes all semantic meaning from the <li> (so think of it like a <div> now).
It would be preferable to move everything "up one level" to keep the DOM tidy though, so a better solution might be:
<ul role="tablist">
<li role="tab" tabindex="0" aria-selected="true" aria-controls="id1">
First tab content...
</li>
<li role="tab">
Second tab content...
</li>
</ul>
This would work as you have now changed the semantic meaning of both the <ul> and the <li>, although it might need a minor adjustment to CSS.
Also Axe can sometimes complain with the first example, even though it is valid, the second example will have no complaints from automated checkers.
Alternatively you may want to look at using <button> elements to create tabs, see the tabs example on W3 on how to structure that.
It has the advantage that the click handler can be used for both mouse and keyboard interactions because you are using a <button>.
Related
Hello i am new to accessibility and i was checking a sidebar like component with axe dev tools, i got this issue: Nested interactive controls are not announced by screen readers.
i was wondering ho i could fix it as i dont understand how else to write it in order to make it accessible heres an example of the code
<nav>
<ul role="tablist" aria-label="menu">
<li role="tab" aria-selected="true">
<a tabindex="-1">Some link</a>
</li>
<li role="tab" aria-selected="true">
<a tabindex="-1">Some link</a>
</li>
<li role="tab" aria-selected="true">
<a tabindex="-1">Some link</a>
</li>
<ul>
<nav>
A tab widget is considered an interactive element. You click on one to switch tabs in a tab navigator. Having a nested element within the tab (in your case, a link <a>) would be weird because clicking on the link might activate the link or it might activate the tab. It's confusing.
See the tab pattern at https://www.w3.org/TR/wai-aria-practices/#tabpanel and also the associated example at https://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-2/tabs.html. You'll see that they use <button> elements for the tabs instead of list elements. You can use a list if you want but the element with role="tab" must be clickable (including via a keyboard) and shouldn't have a nested element that can also be clicked on.
Perhaps your links were supposed to be in the tab panel that displays after selecting on the tab selector?
I'm having a hard time with a custom dropdown menu I made. I'm trying to make it keyboard accessible, but I'm not having much luck with the listbox option. I'm following the instructions I find under WCAG pages, but I'm not having any luck. Here's one of the dropdowns on my page:
<ul class="custom__options dropdown story-selector" id="storyFilter">
<li class="custom__option selected" data-type="all" tabindex="0">All</li>
<li class="custom__option" data-type="news" tabindex="0">News and media</li>
<li class="custom__option" data-type="analysis" tabindex="0">Analysis</li>
<li class="custom__option" data-type="press" tabindex="0">Press releases</li>
</ul>
Here's a working Codepen to play with.
Your Codepen example uses WAI-ARIA attributes but have missing roles and expected keyboard behaviours.
In order to be accessible, all elements must have a minimum of a role and a name.
Your role sets a promise to the user of what kind of element the thing is and sets an expectation of how that thing will behave. Consider a role of "slider". In that single word, you've conveyed a lot of information to the user as to what that component is and how it would behave.
The name helps the user to understand the purpose of the element. The name of a volume slide would be "Volume".
Related attributes and properties are typically applied to one element, or are implied through coded relationships (using aria-labelledby for example). You would not do the following in HTML, for example:
<span alt="My image's text alternative">
<img src="image.png">
</span>
Yet I see things like this often for ARIA menubar implementations:
<li role="menuitem">
Home
</li>
There are options here, but with similar markup, the following would be more appropriate for the interactive menuitem:
<li role="none">
<button role="menuitem" aria-haspopup="true">Home</button>
</li>
It's best to use HTML elements with the closest semantics to what you are hoping to achieve, hence using the <button> element above. A lot of accessibility comes for free when you take this approach, since browsers add many (or all) of the behaviours expected by the user.
If you were to do the above using <div> and <span> elements, you need to enable appropriate keyboard focus and handle both mouse and keyboard events.
<div role="menuitem" aria-haspopup="true" tabindex="0">Home</div>
The W3C's WAI-ARIA Authoring Practices details approaches and expectations for common design patterns. For example, if you have several top-level items to choose from, you would want to use a Navigation Menubar.
Based on the Codepen example, what you are looking for is probably something like a Menu Button (or this alternative Menu Buttons tutorial), since you only requite a single dropdown menu rather than a whole menubar. This would produce something like the following:
<button aria-expanded="false" aria-haspopup="true">Story type</button>
<div role="menu">
<button role="menuitem">Home</button>
<button role="menuitem">All</button>
<button role="menuitem">News and media</button>
<button role="menuitem">Analysis</button>
<button role="menuitem">Press releases</button>
</div>
I have a role="combobox", which opens up a role="listbox" when something is typed. The listbox has a list of items where the <li> are marked as role="presentation" and the children element as role="option". The list items in this case have 2 bits of information, a primary text and a secondary text. should these list items simply be divs, or is there a better semantic element which can be used?
<input role="combobox" aria-haspopup="true" aria-autocomplete="list" ... />
<ul role="listbox">
<li role="presentation">
<div role="option">
<div> primaryText </div>
<div> sencondaryText </div>
</div>
</li>
</ul>
Is there a more semantic way to represent the primary and secondary text?
In a similar scenario, when search results are shown, I have seen each search result is an <article>, the title is either <header> or <h1>, and the secondary text is regular <div>. Does that structure make sense here?
Also, in some cases the results need to have a title, for example: "Results"
In that case I usually change the structure to:
<input role="combobox" aria-haspopup="true" aria-autocomplete="list" ... />
<div class="container">
<div> Results </div>
<ul role="listbox">
<li role="presentation">
<div role="option">
<div> primaryText </div>
<div> sencondaryText </div>
</div>
</li>
</ul>
</div>
In this case would it make sense to use a <section> like this
<input role="combobox" aria-haspopup="true" aria-autocomplete="list" ... />
<section class="container">
<header> Results </header>
<ul role="listbox">
<li role="presentation">
<div role="option">
<div> primaryText </div>
<div> sencondaryText </div>
</div>
</li>
</ul>
</section>
UPDATE:
As mentioned here:
https://www.w3.org/TR/wai-aria-practices-1.1/#presentation_role
Any children of the role="option" would behave as if they have role="presentation" applied to them, so doesn't matter whether they are divs or spans or heading tags, the semantics would be removed.
should these list items simply be divs, or is there a better semantic element which can be used?
<li> is certainly one of the best fit for the items of your list box, except if individual results are quite long (see below) with your third question.
Is there a more semantic way to represent the primary and secondary text?
As far as I know, no. You may use <dl>, <dt>, <dd> instead of <ul>, <li>.
Both are correct solutions, none is better than the other, between the two.
In a similar scenario, when search results are shown, I have seen each search result is an <article>, the title is either <header> or <h1>, and the secondary
text is regular <div>. Does that structure make sense here?
It depends on how the results are going to be navigated.
If you are in the context of a form and if the results are navigated through by using arrow keys, which is the case for a typical combobox, the construction with <article> and headings is much less appropriate.
If you enter something to search, and then go out of the form to read the results, then <article> and headings is the best option, much better than simple <ul> <li>, because screen reader users can use keyboard shortcuts to navigate by heading or by section.
The length of the primary and secondary texts might be a criteria to help you decide which is the best option for your case.
For example, Google search results are used like the later, that's why they use a markup with headings.
Also, in some cases the results need to have a title, for example: "Results" In that case I usually change the structure to:
...
In this case would it make sense to use a like this
Yes, in this case it makes perfect sense.
What can be done to improve the accessibility of a breadcrumb menu similar to:
<ul class="breadcrumbs" aria-label="breadcrumb navigation" role="navigation">
<li>Home</li>
<li>News</li>
<li class="unavailable">#Model.Title</li>
</ul>
Given in this example Home is the site root, News is the first child, and the unavailable class is the current item the /news/article item.
Is there anything that could be done to improve this such as using rel attributes or aria-level attributes?
I would avoid the use of aria-level and use a <ol> element instead. It is best to avoid using aria attributes wherever a native alternative exists. Using aria adds an extra layer of complexity. Simple HTML is far better and already has semantics that are surfaced to AT. This is the first rule of ARIA.
Borrowing from the WAI-ARIA-Practices document, breadcrumbs would look like something like this:
<nav aria-label="Breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="../../">
WAI-ARIA Authoring Practices 1.1
</a>
</li>
<li>
<a href="../../#aria_ex">
Design Patterns
</a>
</li>
<li>
<a href="../../#breadcrumb">
Breadcrumb Pattern
</a>
</li>
<li>
<a href="./index.html" aria-current="page">
Breadcrumb Example
</a>
</li>
</ol>
</nav>
Some notes:
Wrapping the breadcrumbs in a <nav> element lets screen reader users quickly find and jump to the breadcrumbs.
Using <ol> element surfaces an order to screen reader users.
The <ol> should be a child of the <nav>. Some implementations apply role="nav" to the <ol> itself. This is wrong and will override the default <ol> semantics.
aria-current informs screen reader users that this is the current page. If the last breadcrumb for the current page is not a link, the aria-current attribute is optional.
Going from using a screen reader and reading this blog post, the rel attributes won't make a difference to A.T. As for using aria-level, it works if you put it on the anchor tags. I'd also advise wrapping the list in a nav element, for semantic purposes and to save the need of putting a navigation role on the list when you don't need to.
I wound up with this markup for what I think is a not-too-bad breadcrumb. Hide the bullets using CSS (I didn't stop to do that I'm afraid) and I'd say its good.
<nav aria-label="breadcrumb" role="navigation">
<ul>
<li>Home</li>
<li>News</li>
</ul>
</nav>
Hope this helps!
You can use like below
<nav role="navigation" aria-label="breadcrumbs">
<p id="breadcrumblabel">You are here:</p>
<ol id="breadcrumb" aria-labelledby="breadcrumblabel">
<li>Home</li>
<li>Menu1</li>
<li>Menu2</li>
</ol>
</nav>
When searching the Web for a thorough solution on accessible breadcrumbs, #Craig Brett's solution seemed good at first sight. But after reading several sources, aria-level seems to be misused there (besides a W3C Validation problem, see my comment above).
Therefor I like to propose this approach:
<nav aria-labelledby="bc-title" role="navigation">
<h6 id="bc-title" class="vis-off">You are here:</h6>
<a href="~/" aria-labelledby="bc-level-1">
<span id="bc-level-1" class="vis-off">Homepage Website-Title </span>Home
</a>
<a href="~/news" aria-labelledby="bc-level-2">
<span id="bc-level-2" class="vis-off">Level 2: News </span>News
</a>
#Model.Title
</nav>
In this solution we have an HTML5 sectioning element (nav), which should have a heading, and *tada* there it is. Class vis-off signifies an element that is just available to screen readers. With aria-labelledby I'm telling the screen reader to read that headline.
In contrast to Chris' solution, either the <ul> or aria-level is gone.
I'd so or so go for an <ol> if necessary, because the items are in order. Better leaving it out, otherwise it gets very verbose in many screen readers on every page ("List item 1…").
aria-level seems to be misused in the solution above in my understanding. It must be child of a role attribute like f.e. role="list" and that role just signifies not structurally marked-up non-interactive lists.
Maybe a role treeitem might be more appropriate. IMHO it's overkill.
PS: I'm not using BEM notation here to shorten the ids and classes for readability.
Recently I've been implementing ARIA into a web application and I found this question to be quite helpful in the improving the navigation parts.
After implementing this in all modules, I discovered this HTML validation error:
Attribute aria-selected not allowed on element a at this point.
Looking at the ARIA specification, I see that aria-selected is only used in roles gridcell, option, row, and tab. In my case, the role of the link is menuitem.
This is a representative sample of the HTML code:
<nav role=navigation>
<ul role=menubar>
<li role=presentation><a href='page1.php' role=menuitem>Page 1</a></li>
<li role=presentation><a href='page2.php' role=menuitem>Page 2</a></li>
<li role=presentation><a href='page3.php' role=menuitem aria-selected=true>Page 3</a></li>
<li role=presentation><a href='page4.php' role=menuitem>Page 4</a></li>
</ul>
</nav>
As you can see, this is taken on "page 3".
What is the correct ARIA role to use here?
you may also use aria-current="page" for describing current displayed page among navigation items.
I believe that aria-selected is for 'widgets' that are one-tab stop, like a set of tabs that you then arrow around to select. The selected aspect is about which one is in focus, not which page you are on.
I would check out this as a well tested example:
http://whatsock.com/tsg/Coding%20Arena/ARIA%20Menus/Horizontal%20(Internal%20Content)/demo.htm
From: http://whatsock.com/tsg/
For showing the current page I would probably use a more traditional method: Make it not a link. E.g:
<li><a href='page2.php'>Page 2</a></li>
<li><strong>Page 3</strong></li>
This also prevents people from clicking on the same-page link by accident (which I see quite often in usability testing). You can apply the same CSS to nav ul a and nav ul strong and then override the styling for the strong.
Short answer: you can use aria-current="page" or aria-current="location" to indicate the current link in a list of links.
Your pagination component could be improved in terms of accessibility (you can see this as a variation of the similar breadcrumbs pattern):
<nav aria-label="pagination">
<ol>
<li>
Page 1
</li>
<li>
Page 2
</li>
<li>
Page 3
</li>
<li>
Page 4
</li>
</ol>
</nav>
A few notes:
Use <nav> to automatically use the navigation landmark (<nav> is equivalent to <div role="navigation"> but shorter and more elegant)
Use aria-label to provide a meaningful name to the <nav> (most likely, you have more <nav> elements on the page and you should label each one accordingly).
Use to make the set of links structured. This can also help screen reader users as it will be announced as "pagination, navigation (next) list, 4 items, helping users understand how many pages there are.
Use aria-current="location"oraria-current="page"` current page of the list (this is most likely shown in a different style as the other pages, but we need to mark it for screen reader users).