I'm doing some prototyping of a html table and I'm trying to figure out the best way to make it as accessible as possible. The only tricky thing about the table is it has different sections within itself.
This is probably best realized when you see the prototype and can visualize the table: https://jsfiddle.net/3k79wmjg/4/
Each black row is a table section and the rows that follow are related to that section.
The table is still pretty simple, for accessibility I have row and col scopes on <th>
elements, but I'm not sure what the best way is to tie each table section to its accompanying rows of data. How do I provide that context?
What I've done is used the aria-describedby
attribute to tie the <th scope="row">
row to its table section:
<tr class="section-heading">
<th id="hospitalization" colspan="4">Hospitalization</th>
</tr>
<tr>
<th scope="row" aria-describedby="hospitalization">First 60 days</th>
<td>All but $1,600</td>
<td>$0</td>
<td>$1,600<br>(Part A deductible)</td>
</tr>
The aria-describedby
is only on that first table section (hospitalization).
Is this a good idea? Bad idea? What can I do to make this table more accessible to screen readers?
Here's the full html from the prototype (fiddle link above):
<table>
<caption>Medicare Part A</caption>
<thead>
<tr>
<td class="bkg-none"></td>
<th class="bkg-primary" scope="col">Medicare pays</th>
<th class="bkg-primary" scope="col">Plan pays</th>
<th class="bkg-secondary" scope="col">You pay</th>
</tr>
</thead>
<tbody>
<!--start table section-->
<tr class="section-heading">
<th id="hospitalization" colspan="4">Hospitalization</th>
</tr>
<tr>
<th scope="row" aria-describedby="hospitalization">First 60 days</th>
<td>All but $1,600</td>
<td>$0</td>
<td>$1,600<br>(Part A deductible)</td>
</tr>
<tr>
<th scope="row" aria-describedby="hospitalization">61st through 90th day</th>
<td>All but $400 per day</td>
<td>$400 per day</td>
<td>$0</td>
</tr>
<tr>
<th scope="row" aria-describedby="hospitalization">91st day and after:<br>While using 60 lifetime reserve days</th>
<td>All but $800 per day</td>
<td>$800 per day</td>
<td>$0</td>
</tr>
<!--start table section-->
<tr class="section-heading">
<th colspan="8">Once lifetime reserve days are used</th>
</tr>
<tr>
<th scope="row">Additional 365 days</th>
<td>$0</td>
<td>100% of Medicare eligible expenses</td>
<td>$0</td>
</tr>
<tr>
<th scope="row">Beyond the additional 365 days</th>
<td>$0</td>
<td>$0</td>
<td>All costs</td>
</tr>
<!--start table section-->
<tr class="section-heading">
<th colspan="8">Skilled nursing facility care</th>
</tr>
<tr>
<th scope="row">First 20 days</th>
<td>All approved amounts</td>
<td>$0</td>
<td>0</td>
</tr>
<tr>
<th scope="row">21st through 100th day</th>
<td>All but $200 per day</td>
<td>$0</td>
<td>Up to $200</td>
</tr>
<tr>
<th scope="row">Lorem ipsum dolor sit amet, consectetur adipiscing elit</th>
<td>Lorem ipsum dolor</td>
<td>$0</td>
<td>$0</td>
</tr>
<tr>
<th scope="row">Lorem ipsum dolor sit amet, consectetur adipiscing elit</th>
<td>Lorem ipsum dolor</td>
<td>$0</td>
<td>$0</td>
</tr>
<tr>
<th scope="row">Lorem ipsum dolor sit amet, consectetur adipiscing elit</th>
<td>Lorem ipsum dolor</td>
<td>$0</td>
<td>$0</td>
</tr>
<tr>
<th scope="row">Lorem ipsum dolor sit amet, consectetur adipiscing elit</th>
<td>Lorem ipsum dolor</td>
<td>$0</td>
<td>$0</td>
</tr>
<!--more sections and rows-->
<tr>
<td colspan="4" style="text-align:left;"><em>more sections/rows...</em></td>
</tr>
</tbody>
</table>
We are beyond basic WCAG recommendations here.
First of all, I would put table section headings as real headings. In my sense it's the minimum you could do:
<tr>
<td colspan="8"><h2>First 60 days</h2></td>
</tr>
Secondly, if possible, put each section in its own separate table. This will allow you to put each section in a real <section>
element, which in turn will allow you to create region landmarks that facilitate navigation.
This will also save you from implementing the third point below, which can be thedious.
Third, you can set an id on the section heading, and repeat that id in each of the cells of the section. This will make screen readers repeat the section heading at every cell, but for an entire section, it may actually be more annoying than useful. The best is to test the usefulness with real screen reader users.
Be also aware that you need to repeat all involved headers all the time, as it will completely override simple col/row scopes. It's better to still keep col/row scopes for screen readers which don't support advanced headers, though.
<tr>
<th> </th>
<th scope="col" id="col1">Plan 1</th>
<th scope="col" id="col2">Plan 2</th>
<th scope="col" id="col3">Plan 3</th>
...
</tr>
<tr>
<td colspan="8"><h2 id="sec1">First 60 days</h2></td>
</tr>
...
<tr>
<th scope="col" id="row1">...</th>
<td headers="sec1 col1 row1">$1600</td>
<td headers="sec1 col2 row1">$1200</td>
<td headers="sec1 col3 row1">$1200</td>
...
</tr>