Correct scope attribute on tables
Last updated:
Related Guides
The scope attribute must be used only on th cells with valid values
Use the scope attribute only on table header cells (th) and set it to a valid value. This applies to data tables that convey relationships between headers and data. Incorrect scope usage confuses screen readers and slows navigation for blind users and others who rely on assistive technology.
Why It Matters
Screen reader users depend on header associations to understand which header applies to each cell. If scope is missing or wrong, the wrong header may be announced, causing errors.
People with low vision who zoom or use screen readers benefit from clear, consistent header context. Proper scope reduces cognitive load by announcing the right header automatically as users move across cells.
This supports WCAG 2.2 Success Criterion 1.3.1 (Info and Relationships) by ensuring programmatic relationships are exposed.
Common Causes
- Adding scope to td cells instead of th header cells.
- Forgetting scope on row headers in the first column.
- Using invalid values (e.g.,
scope="column"orscope="rowheader"). - Mixing scope with headers/id inconsistently on the same table.
- Applying header markup to layout tables that shouldn’t have data relationships.
- Complex/merged headers where scope alone cannot express relationships.
How to Fix
- Confirm it’s a data table
- If the table is for layout, remove th, scope, and other data-table semantics.
- Mark header cells correctly
- Convert header cells to th.
- For column headers (usually the first row), add
scope="col". - For row headers (usually the first column), add
scope="row".
- Use valid attributes
- In HTML5, scope is only allowed on th (do not place scope on td).
- HTML4 technically allows scope on td, but recommend using th only for compatibility.
- Valid scope values are col, row, colgroup, rowgroup. Recommendation: use col and row; assistive tech support for colgroup/rowgroup is inconsistent.
- Handle complex tables
- If you have grouped or multi-level headers, prefer headers/id associations for reliable mapping between cells and headers.
- Avoid spanning/merged headers unless necessary; keep structures simple when possible.
- Provide helpful context
- Include a concise
<caption>describing the table’s purpose. - Optionally use
<thead>,<tbody>, and<tfoot>for structure (does not replace scope or headers/id).
- Include a concise
How to Test
Keyboard check
- Tab through any interactive elements inside the table; focus order should follow the visual reading order.
- Ensure there are no keyboard traps inside the table.
Screen reader check (desktop)
- With NVDA or JAWS, navigate into the table and use table navigation commands to move by row and column.
- As you move, confirm the correct row and/or column header is announced for each data cell.
- Check multi-level headers carefully; if announcements are wrong or incomplete, use headers/id.
Mobile/touch check
- With VoiceOver (iOS) or TalkBack (Android), navigate cell by cell.
- Confirm that the correct header(s) are announced as you move across rows and columns.
Quick checklist for testers
- Header cells are th.
scope="col"is set on column headers;scope="row"on row headers.- No scope attributes on td.
- Complex tables announce correct headers; use headers/id if needed.
- Table caption accurately describes the table.
Good Example
<table>
<caption>Fall Workshop Schedule</caption>
<thead>
<tr>
<th scope="col">Time</th>
<th scope="col">Room A</th>
<th scope="col">Room B</th>
<th scope="col">Room C</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">09:00</th>
<td>Intro to HTML</td>
<td>Design Basics</td>
<td>Project Kickoff</td>
</tr>
<tr>
<th scope="row">10:30</th>
<td>CSS Layouts</td>
<td>Color Theory</td>
<td>User Interviews</td>
</tr>
<tr>
<th scope="row">13:00</th>
<td>Forms & Validation</td>
<td>Iconography</td>
<td>Workshop Q&A</td>
</tr>
</tbody>
</table>Bad Example
<table>
<caption>Workshop Sessions</caption>
<tr>
<td scope="col">Time</td>
<td scope="column">A</td>
<td>B</td>
</tr>
<tr>
<td>09:00</td>
<td>Intro</td>
<td>Design</td>
</tr>
</table>Problems in the bad example
- scope is placed on td cells.
- Invalid value
scope="column"used. - Row headers are not marked as th with
scope="row". - Column headers are not th with
scope="col".
Quick Checklist
- Use th for all header cells; never put scope on td.
- Set
scope="col"on column headers;scope="row"on row headers. - Stick to row/col; avoid rowgroup/colgroup unless thoroughly tested.
- For complex headers, use headers/id to map data cells to all applicable headers.
- Include a clear caption and keep table structure simple.
- Do not add header semantics to layout tables.
- Test with at least one desktop and one mobile screen reader.