</>
ValidateHTML

Missing Table Headers

Data tables need <th> (table header) elements to identify what each column or row represents. Screen readers use these headers to announce the context for each cell. Without headers, a screen reader just reads cell values in sequence with no indication of what column or row they belong to.

Why It Matters

A data table without headers is nearly useless for screen reader users. They hear a stream of values with no context. This is a WCAG 2.1 Level A violation. It's especially problematic for complex tables with many columns where context is essential to understand the data.

Common Causes

  • Building the header row with <td> cells and bold styling instead of real <th> elements.
  • Omitting the scope attribute, so the screen reader cannot tell whether a header applies to a column or a row.
  • Using a <table> for visual layout rather than data, which mixes presentation with a structure meant for tabular data.

Code Examples

Inaccessible
<table>
  <tr>
    <td>Name</td>
    <td>Email</td>
    <td>Role</td>
  </tr>
  <tr>
    <td>Alice</td>
    <td>alice@example.com</td>
    <td>Developer</td>
  </tr>
</table>
Accessible
<table>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Email</th>
      <th scope="col">Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>alice@example.com</td>
      <td>Developer</td>
    </tr>
  </tbody>
</table>

How to Fix

  • 1Use <th> elements for header cells instead of <td>.
  • 2Add scope="col" for column headers and scope="row" for row headers.
  • 3Wrap header rows in <thead> and data rows in <tbody> for clarity.
  • 4For complex tables, use the headers attribute on <td> elements to reference specific <th> ids.

Frequently Asked Questions

Why are <th> elements better than bold <td> cells?
Visual boldness means nothing to a screen reader. A <th> programmatically marks a cell as a header, so assistive technology can announce the relevant column or row header before each data cell, giving the values context that styled <td> cells cannot.
When should I use scope="col" versus scope="row"?
Use scope="col" for a header that labels everything in its column (the top row) and scope="row" for a header that labels everything in its row (often the first cell of each row). Scope tells screen readers which direction the header applies.
Should I use a table for page layout?
No. Use CSS grid or flexbox for layout. Layout tables force screen readers to announce meaningless rows and columns. Reserve <table> for genuine tabular data, where headers and scope give the structure real meaning.

Check Your Accessibility Now

Our accessibility checker detects this issue automatically.

Open Accessibility Checker
Recommended

Cloudways · Managed Cloud Hosting

Fix accessibility errors, then deploy on Cloudways managed cloud (AWS, GCP, DigitalOcean).

Free 3-day trial · 30% off 3 months + free site migration with code MIGRATE303

Start free trial

Related Accessibility Errors

View all accessibility errors