Search topics
Tables with a title but no caption
Each table's title is a paragraph above it or a row inside it, not a caption, so a screen reader that jumps to the table hears no name and can't tell it from the one beside it.
<p class="table-title"> The problem
Screen reader users who jump from table to table hear no title, so they can't tell which table they are in.
A shop's delivery page shows two tables, one under the bold title "Standard delivery" and one under "Express delivery". Both have the same columns, Weight and Price, and differ only in their prices. A sighted reader glances at the title and knows which table they are in. A screen reader user who presses T to jump to the next table, as NVDA and JAWS allow, hears something like "Table, 2 columns, 3 rows" for the first one, and the same again for the second. To learn whether "$9" is the standard or the express price, they have to leave the table and read back up the page to the line above it.
The title is shown as belonging to its table, but in the code it is a paragraph that happens to come first. Nothing ties the two together, so the table has no accessible name. Some sites put the title inside the table instead, as a first row with one cell spanning every column. That is no better: the table still has no name, and the title is read as a cell of the data, counted as one more row. WCAG 1.3.1 Info and Relationships requires that a relationship shown on screen is also in the code. For a table's title, the HTML way is the caption element, which WCAG's technique H39 names for exactly this; aria-labelledby makes the same tie with ARIA.
A real heading just above a table is a weaker case: it is in the page's heading structure, and someone reading down the page hears it right before the table. Jumping by table still skips it, though, so tie it to the table too.
The longer the page, the more it matters. A delivery page with two tables costs a little backtracking; a results page, a timetable split by day or a pricing page with a table per region leaves the person reading into every table to find the one they came for, and reading the wrong table's figures if they guess.
1 of 10 groups affected
- No vision (affected)
- Low vision (not affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (not affected)
- Seizures (not affected)
- Without vision A screen reader that jumps straight to a table, or lists the page's tables, says only "table" and its size, so the person has to read into each one, or back up the page, to learn which prices they are hearing.
A paragraph above a table passes every scanner, because nothing says the paragraph is a title. axe has a rule, table-fake-caption, for a first row made of one cell spanning the table, but it is experimental, so it is not part of a standard run, and this audit reports it as a lead for a person to confirm. For the paragraph, this audit raises a lead too: a data table with no name gets one, quoting the short line just above it as the likely title. Whether the line above a table is its title, and whether each name tells the tables apart, needs someone to look. AI code generators often write the title as a heading or a styled div above the table, because that is how the design shows it, and leave out the caption.
Try it
Press Tab to jump from table to table.
Each Tab stands in for a screen reader’s key for the next table (T in NVDA and JAWS). The panel shows what it says as it arrives. Can you tell which table you are in? In Broken 2, count the rows it gives.
Broken Can you fix this?
Standard delivery
| Weight | Price |
|---|---|
| Up to 1 kg | $4 |
| 1 to 5 kg | $7 |
Express delivery
| Weight | Price |
|---|---|
| Up to 1 kg | $9 |
| 1 to 5 kg | $15 |
Screen reader says:
(Tab to a table)
The fix
Make each table's visible title its name: a caption, or aria-labelledby to the title.
- 1Put a data table's visible title in its
caption, or point the table'saria-labelledbyat it. - 2Never draw a title as a row of the table's cells.
- 3Give every table a name that tells it apart from the others on the page.
The title in a paragraph above the table
<p class="table-title">Express delivery</p><table class="rates"> <thead> <tr> <th scope="col">Weight</th> <th scope="col">Price</th> </tr> </thead> <tbody> <tr> <th scope="row">Up to 1 kg</th> <td>$9</td> </tr> <tr> <th scope="row">1 to 5 kg</th> <td>$15</td> </tr> </tbody></table>A caption
<table class="rates"> <caption>Express delivery</caption> <thead> <tr> <th scope="col">Weight</th> <th scope="col">Price</th> </tr> </thead> <tbody> <tr> <th scope="row">Up to 1 kg</th> <td>$9</td> </tr> <tr> <th scope="row">1 to 5 kg</th> <td>$15</td> </tr> </tbody></table>Why this fix: Use native HTML first
The headers are right, but the title is a separate paragraph, so the table has no name. Jumping to it, a screen reader says "Table, 2 columns, 3 rows" and nothing that tells it from the standard delivery table above it.
The title is now the table's caption, its first child, and the caption is the table's name. A screen reader announces "Express delivery, table, 2 columns, 3 rows" as it arrives, and lists the table by that name. Browsers centre a caption by default, so one rule sets it back to the start and keeps the bold title as it was drawn; the page looks the same as before. The paragraph, or the title row, is gone.
Both give the table its visible title as its name and pass 1.3.1. Use a caption: it does the same job with plain HTML, needs no id to keep unique and in step, and keeps the title inside the table, so it moves, hides and prints with it. Keep aria-labelledby for a title that has to stay outside the table, such as a card header with controls in it.
Some cases need a choice beyond the fix itself.
- One caption, first: a
captionmust be the table's first child, and a table has only one. A second line, such as "Prices include tax", can go in the same caption on a line of its own, or in a paragraph tied to the table witharia-describedby. - A heading that is also the title: a caption may hold a heading,
<caption><h3>Express delivery</h3></caption>, so the title is in the heading outline and names the table. Check how your screen readers read it before you rely on it. - Tables in a
figure: when a table is the only content of afigure, HTML says to use thefigcaptioninstead of acaption. Thefigcaptiondoes not name the table, so point the table'saria-labelledbyat it as well, or table navigation won't say it. - No title on screen: 1.3.1 doesn't ask for a name the design doesn't show, but a page with several tables is easier to use with one. Add a visible caption if the design allows, and otherwise an
aria-label. - The old
summaryattribute is obsolete. Put a description in the caption or link one witharia-describedby. - Layout tables: a table used only to place content gets no caption. Give it
role="presentation", or better, replace it with CSS layout.
The headers inside each table are a separate failure, covered by data tables with headers that are only bold text. The two belong in the same table component.
Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.
Verify the fix
5 checks, no mouse.
Test with: Screen reader, Keyboard, Zoom
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the table component changes.
Limits
This is a starting pattern, not a guarantee for every table. Screen readers differ in when they read a caption and how they word a table's size, and not all of them list tables. A name only helps when it says what is in the table: two tables captioned "Prices" are as hard to tell apart as two with no caption.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.