All WCAG rules
WCAG 1.3.1Level ASeriousTables

How to fix: Data tables missing headers

A data table needs header cells: mark each column or row header with a <th> element and a scope="col" or scope="row" attribute, so assistive technology can tell users which header a given data cell belongs to.

What it is

A data table presents information in a grid where each cell's meaning depends on its column and row. WCAG Success Criterion 1.3.1 Info and Relationships requires that the relationships conveyed visually, here, which cells are headers and which are data, also exist in code. The <th> element is how you mark a header cell, and the scope attribute tells the browser whether that header labels a column (scope="col") or a row (scope="row").

When a table is built entirely from <td> cells, a sighted user still infers the headers from position and bold styling, but a screen reader cannot. As the user moves through the grid, assistive technology has nothing to announce alongside each value, so the user hears a stream of disconnected numbers with no idea what column or row they are in.

Not every <table> is a data table. Some are used purely for layout, in which case they should carry role="presentation" (or, better, be replaced with CSS). The requirement applies to genuine data tables, where proper <th> cells, plus scope, turn an unreadable grid into something a screen reader can navigate cell by cell with full context.

Who it affects & why it matters

Screen reader users are affected most. With correct headers, assistive technology announces the relevant column and row header as the user enters each cell ("Q3, Revenue, 48,000"), making a table understandable. Without them, the same table is read as a flat list of values, and the user has to memorize the layout or give up.

It also affects people with cognitive disabilities, who benefit from clear, consistently associated headers, and users of braille displays, which use the header relationships to present tabular data in a navigable form. Proper headers make complex data approachable for everyone.

Tables without headers fail SC 1.3.1, a Level A criterion, the most basic conformance tier, and WCAG 2.1 Level AA (which includes every Level A criterion) is the standard U.S. courts apply to ADA website claims. Broken table semantics are a routine finding in any serious accessibility audit because they are easy to detect programmatically.

Pricing grids, comparison tables, schedules, and reports are often the exact content a visitor came to read, so an unlabeled data table can block the core task on a page. Web accessibility lawsuits keep climbing and disproportionately hit businesses under $25 million in revenue, and adding <th> with scope is typically a small, contained markup change.

How to fix it

  1. Decide whether the table holds real data or is only used for layout; if it is layout, add role="presentation" or rebuild it with CSS instead.
  2. For each data table, identify which cells are column headers and which are row headers.
  3. Change those header cells from <td> to <th>, and add scope="col" to column headers and scope="row" to row headers.
  4. For complex tables with multiple header levels, associate cells explicitly using id on the headers and headers on the data cells.
  5. Re-scan and confirm the table now reports header cells.
Before
<table>
  <tr><td>Plan</td><td>Price</td></tr>
  <tr><td>Pro</td><td>$19</td></tr>
  <tr><td>Agency</td><td>$49</td></tr>
</table>
After
<table>
  <tr><th scope="col">Plan</th><th scope="col">Price</th></tr>
  <tr><th scope="row">Pro</th><td>$19</td></tr>
  <tr><th scope="row">Agency</th><td>$49</td></tr>
</table>

How AccessKnight detects this

AccessKnight inspects every <table> in the parsed document and flags it when all three of these are true: the table contains zero <th> elements, it is not marked role="presentation", and it has more than one row. That combination identifies a genuine data table that is missing header cells, while excluding single-row tables and tables explicitly declared as layout-only. Adding at least one <th> (with appropriate scope), or marking a true layout table role="presentation", resolves the finding.

Frequently asked questions

Is a table missing headers a Level A or AA issue?

It fails WCAG 2.1 Success Criterion 1.3.1 Info and Relationships, which is Level A, the minimum conformance tier. AccessKnight scores it as serious severity because, without header cells, a data table is effectively unreadable for screen reader users.

What is the difference between <th> and <td>?

<th> marks a header cell, the label for a column or row, and assistive technology announces it alongside the related data cells. <td> marks an ordinary data cell. Using <th> with a scope attribute is what creates the header-to-data relationship that screen readers rely on.

I only use a table for layout. Do I still need <th>?

No. If a table is purely for visual layout, it should not have data headers at all; instead add role="presentation" so assistive technology ignores its table semantics, or better, lay the content out with CSS. AccessKnight skips tables marked role="presentation" for this rule.

Do I need scope on every header cell?

For simple tables, scope="col" on column headers and scope="row" on row headers is the clearest way to define the relationships and is strongly recommended. For complex tables with multiple levels of headers, use id on the header cells and headers on the data cells to associate them explicitly.

Is this issue on your site?

AccessKnight scans any page against all 30 WCAG 2.1 rules — including this one — and shows every instance with a fix. Free, no credit card.

Scan my site free →

More WCAG fixes