Give A JSX Data Table Header Cells
ID |
javascript.jsx_table_headers |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
accessibility, jsx, reliability |
Description
Reports a JSX data table whose rows carry no header cell: there is a <td> in the table and no
<th> anywhere in it.
Rationale
A header cell is what makes a table readable without seeing it. A screen reader announces the
header along with each cell ("Role: Owner"), so a table of nothing but <td> is read as a flat run
of values whose meaning was in the top row the reader cannot see. Bold text in the first row looks
like a header and is not one.
A table used purely for layout has no headers by definition. Declaring role="presentation" or
role="none" says so and takes the table out of the accessibility tree, which is the correct fix
for that case rather than adding headers to it.
Only a table whose data cells are visible here is judged: there has to be a <td> in the subtree
before a missing <th> means anything. A table whose rows are built by an expression
(<tbody>{rows}</tbody>) shows no cell in this file, and its header row could be in the same
expression, so it is left alone rather than guessed at. So is a table containing a component, whose
rendered markup is not visible here and is very often the header row itself, and one that spreads an
object into its attributes, since role may arrive at runtime.
The searches stop at the first match and cover the whole table subtree, so headers inside a
<thead> count wherever they sit.
<table> // FLAW - every cell is a td
<tr><td>Name</td><td>Role</td></tr>
<tr><td>Ada</td><td>Owner</td></tr>
</table>
<table> // OK - the first row is headers
<tr><th>Name</th><th>Role</th></tr>
<tr><td>Ada</td><td>Owner</td></tr>
</table>
<table role="presentation">...</table> // OK - declared as layout, not data
<table><TableHead />...</table> // OK - a component may render the headers
Remediation
Mark the cells that name the columns or the rows as <th> instead of <td>, and put the column
headers in a <thead> so the structure is explicit. Add scope="col" or scope="row" to each one
so the association is declared rather than inferred. When the table is really a layout grid, either
declare role="presentation" on it or replace it with CSS grid or flexbox, which carry no table
semantics to correct.