How to fix a table header with no data cells?
th-has-data-cells page
The issue
A screen reader announces a table’s headers alongside its data. A header cell with no data under it or beside it labels nothing, and it is usually a sign the table’s structure is wrong: a header row with no body, a styled title row built from <th>, or every cell marked as a header so the table looks bold.
The person navigating the table hears headers with nothing to describe, or loses track of which header applies where. WCAG 1.3.1 requires the table’s structure to be available to assistive technology, which a table of headers alone doesn’t provide.
Scope
Every visible table with at least one <th> is checked, except layout tables marked role="presentation" or role="none". A header passes when a <td> lists its ID in headers, or when there is a <td> in its row or in its column. In a table with no <td> at all, every header is reported. Columns are matched by each cell’s position in its row, so a row with colspan can shift which column a header is checked against.
How to check you have it
- In probeo: the page reports
th-has-data-cells, “Table headers in a data table must refer to data cells”, as serious, under WCAG 1.3.1. - By hand: for each
<th>, look along its row and down its column for a<td>. - With a tool: axe DevTools has a rule with the same name. The browser’s accessibility tree shows each cell’s role.
The fix
Mark only real headers as <th>, and make sure each one has data cells in its row or column.
If the table is all headers, the data cells were probably marked up as <th> for styling; change them to <td> and style them in CSS. If a header row sits above an empty table, fill the table or remove it. A title row belongs in <caption>.
Done when: every <th> has data cells in its row or column, and the check above comes back clean.
Do not
- Do not use
<th>to make text bold. - Do not use a header cell as the table’s title; use
<caption>. - Do not leave a header row in a table that has no data rows.
FAQ
Is a table used for layout checked?
Not if it is marked role="presentation" or role="none". A layout table without that role is treated as a data table.
Why is a merged header cell reported?
Columns are matched by position, so a colspan in another row can leave a header without a matching data cell. Adding headers to the data cells links them explicitly.
Does this apply to an empty table?
A table with header cells and no data cells reports every header. A table with no <th> isn’t checked by this rule.
Which product detects this
Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.