I have two different captions (say Caption A and Caption B) for a single table that display based on the selection of the radio buttons. My screen reader is reading the default caption 'Caption A', but when I select the other option, it displays the text but fails in reading that caption 'Caption B'.
Below is the code I am trying:
$('#myTable').append("<caption class='cA'>Caption A</caption>");
$('#myTable').append("<caption class='cB hide'>Caption B</caption>");
$('input[type=radio]').change(function() {
if(this.value == 'captionA') {
$('.main-wrapper').find('.cB').addClass('hide');
$('.main-wrapper').find('.cA').removeClass('hide');
}
else if(this.value == 'captionB'){
$('.main-wrapper').find('.cA').addClass('hide');
$('.main-wrapper').find('.cB').removeClass('hide');
}
});
Output:
First time:
Your Caption A Showing 1 to 10 of 10 entries
While selecting the second option, it says:
table Showing 1 to 10 of 10 entries
$('#myTable').append("<caption class='cA'>Caption A</caption>");
$('#myTable').append("<caption class='cB hide'>Caption B</caption>");
$('input[type=radio]').change(function() {
if(this.value == 'captionA') {
$('.main-wrapper').find('.cB').addClass('hide');
$('.main-wrapper').find('.cA').removeClass('hide');
}
else if(this.value == 'captionB'){
$('.main-wrapper').find('.cA').addClass('hide');
$('.main-wrapper').find('.cB').removeClass('hide');
}
});
.sr-only {
position: absolute;
top: -30em;
}
table.sortable td,
table.sortable th {
padding: 0.125em 0.25em;
width: 8em;
}
table.sortable th {
font-weight: bold;
border-bottom: thin solid #888;
position: relative;
}
table.sortable th.no-sort {
padding-top: 0.35em;
}
table.sortable th:nth-child(5) {
width: 10em;
}
table.sortable th button {
position: absolute;
padding: 4px;
margin: 1px;
font-size: 100%;
font-weight: bold;
background: transparent;
border: none;
display: inline;
right: 0;
left: 0;
top: 0;
bottom: 0;
width: 100%;
text-align: left;
outline: none;
cursor: pointer;
}
table.sortable th button span {
position: absolute;
right: 4px;
}
table.sortable th[aria-sort="descending"] span::after {
content: "▼";
color: currentcolor;
font-size: 100%;
top: 0;
}
table.sortable th[aria-sort="ascending"] span::after {
content: "▲";
color: currentcolor;
font-size: 100%;
top: 0;
}
table.show-unsorted-icon th:not([aria-sort]) button span::after {
content: "♢";
color: currentcolor;
font-size: 100%;
position: relative;
top: -3px;
left: -4px;
}
table.sortable td.num {
text-align: right;
}
table.sortable tbody tr:nth-child(odd) {
background-color: #ddd;
}
/* Focus and hover styling */
table.sortable th button:focus,
table.sortable th button:hover {
padding: 2px;
border: 2px solid currentcolor;
background-color: #E5F4FF;
}
table.sortable th button:focus span,
table.sortable th button:hover span {
right: 2px;
}
table.sortable th:not([aria-sort]) button:focus span::after,
table.sortable th:not([aria-sort]) button:hover span::after {
content: "▼";
color: currentcolor;
font-size: 100%;
top: 0;
}
.hide{display: none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<div >
Sample test
<a href="#">tttttt</a>
<div role="radiogroup">
<label >
<input name="test" type="radio" value="captionA" checked="checked">Opt A
</label>
<label >
<input name="test" type="radio" value="captionB">opt B
</label>
</div>
<table id="myTable" >
<thead>
<tr>
<th>
<button>
First Name
<span aria-hidden="true"></span>
</button>
</th>
<th aria-sort="ascending">
<button>
Last Name
<span aria-hidden="true"></span>
</button>
</th>
<th>
<button>
Company
<span aria-hidden="true"></span>
</button>
</th>
<th >Address</th>
<th >
<button>
Favorite Number
<span aria-hidden="true"></span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fred</td>
<td>Jackson</td>
<td>Canary, Inc.</td>
<td>123 Broad St.</td>
<td >56</td>
</tr>
<tr>
<td>Sara</td>
<td>James</td>
<td>Cardinal, Inc.</td>
<td>457 First St.</td>
<td >7</td>
</tr>
<tr>
<td>Ralph</td>
<td>Jefferson</td>
<td>Robin, Inc.</td>
<td>456 Main St.</td>
<td >513</td>
</tr>
<tr>
<td>Nancy</td>
<td>Jensen</td>
<td>Eagle, Inc.</td>
<td>2203 Logan Dr.</td>
<td >3.5</td>
</tr>
</tbody>
</table></div>
Based on the condition, it changes the text but does not read the second caption. Am I missing anything here?
CodePudding user response:
So I’ve been trying to reproduce the issue, and it seems that Firefox correctly exposes the changed caption through the accessibility API, both with Orca and NVDA.
Chrome and Edge don’t, with NVDA.
The issue might be related to a referenced element being exchanged for another (<caption>
). Changing DOM which is used to calculate accessible names is always a bit dangerous.
What I found to work also with Chrome and Edge was to additionally set the aria-label
of the table to the same contents.
const table = document.querySelector('table');
const captions = document.querySelectorAll('caption');
document.querySelectorAll('input[type="radio"]').forEach(el => el.addEventListener('change', e => {
captions.forEach(el => el.hidden = true); // stubbornly hide all first
// then figure out which one to show
const caption = document.querySelector('#caption-' e.currentTarget.value);
caption.hidden = false;
table.setAttribute('aria-label', caption.textContent);
}))
<fieldset>
<legend>Choose caption</legend>
<label><input type="radio" name="caption" value="a" checked> Caption A</label>
<label><input type="radio" name="caption" value="b"> Caption B</label>
</fieldset>
<table>
<caption id="caption-a">Caption Alpha</caption>
<caption id="caption-b" hidden>Caption Bravo</caption>
<thead>
<tr>
<th>
<button>
First Name
</button>
</th>
<th aria-sort="ascending">
<button>
Last Name
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fred</td>
<td>Jackson</td>
</tr>
<tr>
<td>Sara</td>
<td>James</td>
</tr>
</tbody>
</table>