Skip to main content
Accessibility AccessLint 0.16

Table headers should be associated with data cells.

About this AccessLint rule

Table header cells (<th>) in HTML exist to label the data in a table's rows or columns. When a <th> element has no associated data cells (<td> or elements with a cell role), it describes nothing. Screen readers rely on header-to-cell associations to announce context as users navigate through a table. For example, when a user moves to a cell containing "05:41", the screen reader reads the column header "Time" along with it, producing something like "Time: 05:41". If no data cells exist for the header to describe, that association breaks, and the header becomes meaningless noise.

This rule applies to any element with a columnheader or rowheader semantic role that is visible, included in the accessibility tree, and inside a table or grid that is also in the accessibility tree. The element must be assigned to at least one cell. A "cell" here includes elements with the roles cell, gridcell, columnheader, or rowheader.

Who is affected

Screen reader users are the primary group affected. When navigating a table, screen readers like JAWS, NVDA, and VoiceOver use header cells to provide context for each data cell. A table that contains only headers and no data cells confuses this navigation model. The screen reader announces headers without any associated content, making the table structure unintelligible.

Users who rely on other assistive technologies that parse table semantics can also be affected.

Relevant WCAG success criteria

This rule maps to WCAG 2.1 Success Criterion 1.3.1: Info and Relationships (Level A). This criterion requires that information, structure, and relationships conveyed through presentation can be programmatically determined. A <th> element conveys that it is a header for some data, but if no data cells exist, that structural relationship is empty. The programmatic structure does not match the intended content.

A failure of this rule means SC 1.3.1 is not satisfied. A pass does not guarantee full conformance on its own, since other aspects of the table structure may still need review.

How to fix it

The fix depends on why the table has headers without data cells.

If the table is supposed to contain data but the <td> elements are missing, add the appropriate data cells. Every <th> should have at least one <td> (or role="cell" element) associated with it in the same column or row.

If the content is not actually tabular data, remove the table markup entirely. Use headings, lists, <div> elements, or other appropriate HTML instead. Tables should only be used for data that has a two-dimensional relationship between headers and values.

If you are using ARIA roles to create a custom table (role="table", role="row", etc.), make sure that every element with role="columnheader" or role="rowheader" has at least one sibling or descendant element with role="cell" or role="gridcell" in the corresponding position.

Examples

Incorrect: table with headers but no data cells

This table has two <th> elements but no <td> elements. The headers describe nothing.

<table>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</table>

Correct: table with headers and data cells

Each <th> now has corresponding <td> elements in the rows below.

<table>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
<tr>
<td>John</td>
<td>john@example.com</td>
</tr>
</table>

Incorrect: ARIA table with column headers but no cells

The columnheader elements have no corresponding cell elements.

<div role="table" aria-label="Schedule">
<div role="row">
<span role="columnheader">Day</span>
<span role="columnheader">Time</span>
</div>
</div>

Correct: ARIA table with column headers and cells

Each columnheader now has associated cell elements in subsequent rows.

<div role="table" aria-label="Schedule">
<div role="rowgroup">
<div role="row">
<span role="columnheader">Day</span>
<span role="columnheader">Time</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="cell">Monday</span>
<span role="cell">09:00</span>
</div>
</div>
</div>

Correct: content that is not tabular uses non-table markup

If the content was never meant to be a table, use appropriate semantic HTML instead.

<h2>Name</h2>
<p>John</p>
<h2>Email</h2>
<p>john@example.com</p>

Correct: header with a colspan data cell

A single <td> that spans multiple columns satisfies both <th> elements.

<table>
<thead>
<tr>
<th>Projects</th>
<th>Exams</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2">15%</td>
</tr>
</tbody>
</table>

Detect accessibility issues automatically

Rocket Validator scans your site with complementary accessibility engines, helping teams find issues across every page.

Help us improve our guides

Was this guide helpful?
๐ŸŒ Trusted by teams worldwide

Validate at scale.
Ship accessible websites, faster.

Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.

Scheduled Reports
API Access
Open Source Standards
$7 / 7 days

Pro Trial

Full Pro access. Cancel anytime.

Start Pro Trial โ†’

Join teams across 40+ countries