Uniquely Labeling Fields in a Table
Many of my clients over the years have relied on fields in tables. Sometimes a checkbox to select a row, sometimes text inputs to update information, sometimes buttons select something. Rarely are they interested in a block of label text above the field, and I cannot disagree with them.
The challenge here is to create a unique name for each field without repeating text all over your screen. Experience has taught me that when clients try to visually hide
<label> text, it can fall out of sync with the column or row headers, making it even more confusing.
The good news here is that if you are creating tables correctly, there isn’t much extra work you need to do. Your column and row headers, paired with some ARIA, can do the job for you. I made a demo to show it in action, embedded below or directly at Codepen.
There are two sets of thing happening here:
- Each column needs a
<th>and each row needs a
<th scope="row">, each with a unique
- Each field needs an
aria-labelledbypointing to the
ids of the column and row header (separated by a space).
The order of the
id values in the
aria-labelledby matters. Note that the
aria-labelledby code for the
<button> flips the order of the
ids referenced by
aria-labelledby in order to provide a more natural announcement to screen reader users (“Remove 1” versus “1 Remove”). The
<button> references its own
id attribute instead of the column header, though this is a decision you should make based on if the button text is different from the column header or likely to change based on errors or user input.
The fields are verbose for screen reader users who use table navigation, but that is a trade-off for users who tab through the fields. While this approach can make it a pain for voice users to select fields, hidden labels will always cause that challenge. An explanation of the naming convention can mitigate that.
Note that all the fields on this form are nonsense, the table is not responsive, and errors are not shown. These are strictly accessible, but maybe using row headers of strictly numbers is not the most usable option depending on your table. In no way would this example warrant an ARIA grid role.
Update: 22 June 2019
John made a great point in the comments. Maybe some of the labels would make more sense in my example if they pointed at the author name instead of an assigned number. After all, the row number announced with the assigned number feels like a permanent off-by-one error and may have muddied the point I was trying to make.
So I removed the first column, made the row header the second column, and used that as the assigned name. Note that in some browser and screen reader combinations, row headers that are not the first column are not announced for any cells in columns prior to the row header.
I also made a video.
I looked at this quickly because I had to get back to work but wouldn’t it be better connect the items to the author’s name instead of the row number, that way it would read “Remove Mary Shelley” instead of “Remove 2”?
Yes, John, yes it would.
Granted, each table would be different and, as you have pointed out, not every bit of labeling is best leaning on a row header when there is another cell that may make more sense in that context for those users.
For those following along, to make that work the
<td>will also need a unique
id, which will then be referenced in the