reala11y GUIDES Accessible datatables inWordPress: th… Nov 8, 2022

November 8, 2022 · reala11y team

Accessible data tables in WordPress: th, scope, captions

How to build accessible data tables in WordPress content with proper th headers, scope, and captions — plus how to tell when you shouldn't use a table at all.

Data tables are one of the most common accessibility failures we see in published WordPress content. Not because tables are hard, but because the block editor makes it trivially easy to produce a grid of cells that looks like a table while carrying none of the structure a screen reader needs to navigate it.

A sighted reader scans a table in two dimensions at once: they glance up a column and across a row to understand what any single cell means. A screen reader user gets that same two-dimensional context only if the markup encodes it. Get the structure right and the table reads as “Revenue, Q3, $48,000.” Get it wrong and it reads as “$48,000” with no anchor at all.

The markup that actually matters

A real data table needs three things most authored tables are missing.

1. Header cells, not bold body cells

Every column and row label belongs in a <th>, not a <td> styled to look heavier. The <th> element is what tells assistive technology “this cell labels other cells.” Visual weight does nothing for a screen reader.

<th>Quarter</th>   <!-- a header -->
<td><strong>Quarter</strong></td>  <!-- just bold text -->

The WordPress core Table block does support header rows and footer rows — enable Header section in the block’s settings sidebar. It does not give you row headers (a <th> in the first column of each body row), so tables where the left-most column labels each row often need a quick pass in the code editor.

2. scope on every header

scope removes ambiguity about which cells a header governs. Use scope="col" for column headers and scope="row" for row headers:

<thead>
  <tr><th scope="col">Plan</th><th scope="col">Price</th></tr>
</thead>
<tbody>
  <tr><th scope="row">Starter</th><td>$5/mo</td></tr>
</tbody>

For simple tables, browsers and screen readers can often infer associations without scope. Adding it anyway is cheap insurance and the right habit, and it becomes essential the moment a table has both row and column headers.

3. A caption

A <caption> is the table’s accessible name — the one-line answer to “what is this a table of?” It sits right after the opening <table> tag and is announced when a user lands on the table:

<table>
  <caption>2026 pricing by plan</caption>
  ...
</table>

The Table block exposes this as the caption field beneath the table. Use it. A heading sitting above the table in the post is not a substitute — it is not programmatically tied to the table.

These structural needs map to WCAG 2.2 success criterion 1.3.1 (Info and Relationships), part of the standard that became a W3C Recommendation on 5 October 2023. Our WCAG 2.2 guide walks through the broader criterion if you want the full picture.

When not to use a table

This is the part most table tutorials skip. The honest answer is that a lot of content marked up as a table should not be a table at all.

Reserve <table> for genuinely tabular data: information that only makes sense as the intersection of a row and a column. If you cannot name what the rows are and what the columns are, you probably do not need a table.

Where reala11y fits

reala11y flags data tables that are missing <th> headers or a <caption> so you can see the problem before a real user hits it. Because table headers and captions carry meaning — the correct text depends on what your data actually represents — this is a detect-and-review issue, not something any tool should silently rewrite. We surface it; a human supplies the labels. That division of labour is deliberate, and it is roughly how the whole product works: reala11y fixes safe, code-level issues automatically and routes judgment calls to you (see how it works).

An honest takeaway

Tables are one of the more checkable accessibility issues — the presence of <th>, scope, and <caption> is easy for tooling to detect, and easy for you to fix. But automated detection only ever covers part of the picture; across all of WCAG, tools catch roughly 30–40% of issues by criteria, and the rest needs a person. A scanner can tell you a header is missing. It cannot tell you whether the header text is right, or whether the thing should have been a table in the first place. Build the structure correctly, lean on tooling to catch the omissions, and keep a human in the loop for the judgment.