Lesson 12 · Part 2 · Tables

Presenting tabular data

Use a table when the data has rows and columns and the reader needs to compare across and down. Mark the headers, and every cell can tell a screen reader which row and column it belongs to.

In one minute

In plain words

Picture a spreadsheet read out loud. If the reader says only "21", you have no idea what it means. A good table is a spreadsheet where every number is read with its labels: "Harbor, Points, 21". Headers are those labels, and the screen reader repeats them for you as you move around.

1. Headers give every cell its labels

Browsers list every table in the accessibility tree (the version of the page that screen readers use) with its rows, columns and header cells. Screen readers offer table keys, such as Ctrl + Alt + arrow keys in NVDA and JAWS, to move cell by cell. The reader then says the header text as you cross into a new row or column. Without th there is nothing to say.

Lab: what is heard on one cell

Step 1. Choose how the table is marked up, then pick a cell with the two selects.


          

Use scope="col" and scope="row" for simple tables. Complex tables with merged cells (colspan or rowspan) can need headers and id instead, but first ask if you can split the table into two simple ones, which is easier for everyone. The <caption> is the table's name: it is read when the user arrives, and it shows up in the screen reader's list of tables (WCAG 1.3.1).

2. Sorting: a button, a state, and a message

A sortable column header holds a real <button>. After a press, three things must be true. The header says which way it is sorted (aria-sort="ascending" or "descending", on one header only). A status message announces the change. And focus stays on the button so the user can press again.

Lab: sort the standings

Step 2. Pick the feedback style, then press a column button with Enter or Space.

Week 12 standings
Region

Press a column button.
Press a column button.

The visible arrow icons you often see on sortable headers should be hidden from screen readers (aria-hidden="true") because aria-sort already carries the meaning. Do not make the whole header row a link. For tables with hundreds of rows, consider paging, and keep the header visible when scrolling.

3. Buttons and links inside cells

Cells can hold controls. Screen reader users often pull up a list of all buttons on the page, and in that list the surrounding row is gone. Ten buttons all named "Edit" are ten identical entries. Add the row to the name, either with visually hidden text or aria-label. Keep the visible text inside the name (WCAG 2.5.3 Label in Name).

Lab: the list of buttons

Step 3. Switch the naming. The list shows what a screen reader's "list of buttons" would contain.

Teams
TeamAction

4. Table, list or layout?

A table says "compare these". If the data does not have that shape, a table is noise: the screen reader announces "table with 5 rows, 2 columns" and then makes the user navigate it. Layout tables (using a table to position things) are out. Use CSS Grid or Flexbox, which do not add table semantics.

Lab: pick the right structure

Step 4. Choose one situation, then say which structure fits.

Situation
Pick a situation, then a structure.

Common mistakes

You seeWhy it is a problemFix
Header cells made with bold tdCells have no labels for a screen reader.th scope="col" / scope="row".
No captionThe table has no name in the list of tables.<caption>, or aria-labelledby pointing at a heading.
Sort changes rows silentlyOrder change is invisible to screen reader users.aria-sort + status message.
Focus moves after sortingUser loses their place and cannot sort again.Leave focus on the button.
Many buttons named "Edit"Identical entries in a button list."Edit Northwind".
Table used for layoutExtra announcements, hard to reflow at zoom.CSS Grid or Flexbox.
Wide table breaks at 400% zoomWCAG 1.4.10 Reflow; data tables may scroll sideways but must stay usable.Wrap in a scrollable region with a label and tabindex="0".
Try it yourself
  1. In lab 2, Tab to "Points" and press Enter twice. Did focus stay on the button each time?
  2. In lab 1, switch to "Column + row th" and read the sentence for each cell. Which one would you want to hear?
  3. If you have a screen reader on, press its "next table" key on a page of your own and listen to the caption.

Remember

Edit this example in the playground