Powered by
Structure & headings
A Table's Scope Attribute Is in the Wrong Place or Misspelt
When `scope` is on the wrong cell or has a made-up value, screen readers can't tell which header goes with each cell, so numbers lose their meaning.
scope-attr-validBest practiceBest practice — not a WCAG requirement, but it helps people all the same.
- Status
- ModerateModerate — An annoyance, with a workaround.CurrentScanners run this rule today.
- Owner
- DevContentTest
- Audit
- Automated+ManualA scanner finds it; a person confirms the fix.
Why it matters
In a data table, scope tells a screen reader whether a header labels a column or a row. Then, as someone moves cell by cell, they hear the right header with each value.
scope only works on header cells (th), with one of four values: col, row, colgroup or rowgroup. Anything else is ignored. People then hear a bare "$20" and have to guess what it means.
Who it affects
| Who | What they experience | Impact |
|---|---|---|
| Screen reader users | They hear a value like "$20" with no header, so they must count rows and columns to work out what it is. | High impact |
| Low-vision users (magnification) | Affected only if they also use a screen reader. Magnifier users see the table as normal. | Partial impact |
Business & product impact
| Area | Why | Impact |
|---|---|---|
| Legal | This rule is a best practice, not a WCAG requirement on its own. But if headers end up unlinked from their data, that can fail WCAG 2.2 Level AA, which Australian Disability Discrimination Act complaints point to. | Moderate impact |
| Conversion | Pricing, plan and comparison tables drive decisions. If people can't follow them, some will leave or call instead. | Moderate impact |
| SEO | Search engines don't reward correct `scope` — don't sell it as an SEO fix. | Low impact |
| Brand trust | A broken comparison table tells screen reader users the site wasn't built for them. | Low impact |
| Cost to fix | Usually a quick edit in the table markup or the table component. Fix the component once. | High impact |
Fixing it in code
Scope on an ordinary cell
Don't
<tr><td scope="col">Plan</td><td scope="col">Price</td></tr>
<tr><td>Basic</td><td>$20</td></tr>A screen reader says: “$20”
Do
<tr><th scope="col">Plan</th><th scope="col">Price</th></tr>
<tr><td>Basic</td><td>$20</td></tr>A screen reader says: “Price, $20”
scope only works on th header cells, so make the headers real th elements.
A made-up scope value
Don't
<th scope="column">Price</th>
<th scope="horizontal">Basic</th>A screen reader says: “$20”
Do
<th scope="col">Price</th>
<th scope="row">Basic</th>A screen reader says: “Basic, Price, $20”
Only col, row, colgroup and rowgroup are understood; anything else is ignored.
Designer's handoff note
In table designs, mark which cells are column headers and which are row headers. Developers then know where th and scope belong.
Only use a table for data with rows and columns, not for page layout.
Quick test
Tool
NVDA (opens in a new tab) (free, Windows)
Checklist
- Pass
- You hear the right header with each value, like "Price, $20".
- Fail
- You hear only the value, like "$20", or the wrong header.
What a green scan still misses
A scanner checks that scope is on a th with a valid value. It can't tell if you chose col where you meant row — for that, listen.
Reference
- Rule ID
scope-attr-valid- Raised by
- axe-core: “scope attribute should be used correctly”
- WCAG
- Best practice — not a WCAG requirement
- Last reviewed
- 14 October 2026