Help with web accessibility problem for screen readers - ARIA
I'm attempting to make my company's online software documentation ADA-accessible. We have several JavaScript elements that are currently not accessible to a screen reader. The one I'm working on...
I'm attempting to make my company's online software documentation ADA-accessible. We have several JavaScript elements that are currently not accessible to a screen reader. The one I'm working on is a set of tabs that show/hide content depending on which one you click. I am trying to use ARIA tags to make the tabs accessible. I have based my code off of this page, with some modifications. Namely, they use <a> tags as the active element and I do not want to use <a> tags.
While I'm able to get the tabs to work fine for me (a sighted person), testing with a screen reader shows mixed results. I can get the tabs to work using the Windows Narrator screen reader on Microsoft Edge in Windows 10, but not Chrome or Firefox in Windows 11. In those configurations, it is impossible to switch tabs. (I haven't tested every possible permutation, but it's probably a browser issue.) I don't know why this is happening because I have set up all my ARIA tags, and it does work on Edge.
Can anyone help me understand what I'm doing wrong so I can debug the issue and improve the code? Requirements are:
- The first tab must be selected (showing content) by default. Other tab content must be hidden by default, except the tab button to click on
- Sighted users must be able to navigate between tabs by clicking on the tab headers via mouse
- Visually impaired users must be able to navigate between tabs via keyboard/screen reader
- The presence, function, and usage of the tabs must be clear to the screen reader
- I do not want to use an
<a>tag nested in the<li>as the active element because this causes the page to jump around when sighted users click on it. I would like the entire "button" (right now, the<li>tag) to be clickable. - Must work on all/most common browsers and popular operating systems
I suspect this is a JS issue, but I'm at a loss here and I don't know how to proceed.
Click to view HTML
<ul class="tabs-list" role="tablist">
<li class="tab current" aria-controls="example-1" aria-selected="true" href="#example-1" id="tab-example-1" role="tab">Example 1</li>
<li class="tab" aria-controls="example-2" aria-selected="false" href="#example-2" id="tab-example-2" role="tab">Example 2</li>
<li class="tab" aria-controls="example-3" aria-selected="false" href="#example-3" id="tab-example-3" role="tab">Example 3</li>
</ul>
<div aria-labelledby="tab-example-1" class="tab-panel current" id="example-1" role="tabpanel">
<p>Example 1 content goes here</p>
</div>
<div aria-labelledby="tab-example-2" class="tab-panel hidden" id="example-2" role="tabpanel">
<p>Example 2 content goes here</p>
</div>
<div aria-labelledby="tab-example-3" class="tab-panel hidden" id="example-3" role="tabpanel">
<p>Example 3 content goes here</p>
</div>
Click to view CSS
ul.tabs-list {
margin-left: 2px;
margin-right: 2px;
padding: 0px;
list-style: none;
position: relative;
line-height: 8pt;
}
ul.tabs-list:after
{
position: absolute;
content: "";
width: 100%;
bottom: 0;
left: 0;
border-bottom: 1px solid #ddd;
}
ul.tabs-list li {
color: #333;
display: inline-block;
padding: 10px 10px;
cursor: pointer;
position: relative;
z-index: 0;
}
ul.tabs-list li.current {
background: #fff;
color: #d9232e;
border-top: 1px solid #ddd;
border-bottom: 0px solid white;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
z-index: 100;
}
ul.tabs-list li:hover {
background: #c2c2c2;
color: #000;
display: inline-block;
padding: 10px 10px;
cursor: pointer;
border: 1px solid transparent;
}
ul.tabs-list li.current:hover {
background: #fff;
color: #d9232e;
margin-left: 0px;
border-top: 1px solid #ddd;
border-bottom: 1px solid transparent;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
z-index: 2;
}
div.tab-panel {
display: none;
background: #ededed;
padding: 15px;
background-color: transparent;
}
div.tab-panel.current {
display: inherit;
}
Click to view JavaScript
$(function(){
var index = 0;
var $tabs = $('li.tab');
$tabs.bind(
{
// on keydown,
// determine which tab to select
keydown: function(ev){
var LEFT_ARROW = 37;
var UP_ARROW = 38;
var RIGHT_ARROW = 39;
var DOWN_ARROW = 40;
var k = ev.which || ev.keyCode;
// if the key pressed was an arrow key
if (k >= LEFT_ARROW && k <= DOWN_ARROW){
// move left one tab for left and up arrows
if (k == LEFT_ARROW || k == UP_ARROW){
if (index > 0) {
index--;
}
// unless you are on the first tab,
// in which case select the last tab.
else {
index = $tabs.length - 1;
}
}
// move right one tab for right and down arrows
else if (k == RIGHT_ARROW || k == DOWN_ARROW){
if (index < ($tabs.length - 1)){
index++;
}
// unless you're at the last tab,
// in which case select the first one
else {
index = 0;
}
}
// trigger a click event on the tab to move to
$($tabs.get(index)).click();
ev.preventDefault();
}
},
// just make the clicked tab the selected one
click: function(ev){
index = $.inArray(this, $tabs.get());
setFocus();
ev.preventDefault();
}
});
var setFocus = function(){
// undo tab control selected state,
// and make them not selectable with the tab key
// (all tabs)
$tabs.attr(
{
tabindex: '-1',
'aria-selected': 'false'
});
// hide all tab panels.
$('.tab-panel').removeClass('current');
// make the selected tab the selected one, shift focus to it
$($tabs.get(index)).attr(
{
tabindex: '0',
'aria-selected': 'true'
}).focus();
// handle <li> current class (for coloring the tabs)
$($tabs.get(index)).siblings().removeClass('current');
$($tabs.get(index)).addClass('current');
// add a current class also to the tab panel
// controlled by the clicked tab
$("#"+$($tabs.get(index)).attr('aria-controls')).addClass('current');
};
});