Skip to content

Table Accessibility Basics — The scope Attribute

A table that looks clear visually may be confusing to a screen reader user navigating cell by cell. The scope attribute tells assistive technology which cells a header applies to — column or row.

A sighted user reads a table by glancing at the column headers, then reading down. A screen reader announces each cell individually. Without explicit connections, the reader may announce “Monday, 9:00 AM” without explaining that “Monday” is a day and “9:00 AM” is a time — because those column headers are not linked to the data cells.

The scope attribute makes that connection explicit.

scope is added to <th> elements. It takes two main values:

ValueMeaning
scope="col"This header applies to all cells below it in the same column
scope="row"This header applies to all cells to the right of it in the same row

Most tables have column headers in the first row. Use scope="col" on each <th>:

<table>
<thead>
<tr>
<th scope="col">Day</th>
<th scope="col">Time</th>
<th scope="col">Location</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monday</td>
<td>9:00 AM</td>
<td>Room 12</td>
</tr>
<tr>
<td>Wednesday</td>
<td>11:00 AM</td>
<td>Room 7</td>
</tr>
</tbody>
</table>

A screen reader navigating this table now knows that “Monday” belongs under the “Day” header, “9:00 AM” belongs under “Time”, and so on.

Some tables have headers in the first column — each row has a label. Use scope="row" on those <th> cells:

<table>
<tbody>
<tr>
<th scope="row">Easy</th>
<td>Under 5 miles</td>
<td>Minimal elevation change</td>
</tr>
<tr>
<th scope="row">Moderate</th>
<td>5–10 miles</td>
<td>Some elevation gain</td>
</tr>
<tr>
<th scope="row">Strenuous</th>
<td>Over 10 miles</td>
<td>Significant elevation gain</td>
</tr>
</tbody>
</table>

Here “Easy”, “Moderate”, and “Strenuous” are row headers — they label what the rest of each row describes.

A table can have both column and row headers:

<table>
<thead>
<tr>
<th scope="col">Rating</th>
<th scope="col">Distance</th>
<th scope="col">Elevation</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Easy</th>
<td>Under 5 miles</td>
<td>Minimal</td>
</tr>
<tr>
<th scope="row">Moderate</th>
<td>5–10 miles</td>
<td>Some gain</td>
</tr>
</tbody>
</table>

The column headers describe what each column contains. The row headers label each row. Together they give assistive technology everything it needs to describe any cell in context.

scope has no visual effect whatsoever. The table looks identical with or without it. It is purely for assistive technologies and semantic correctness — but that is exactly why it matters.

Open index.html in VS Code.

Find your <table> from the previous lessons. Add scope attributes to your <th> elements.

  1. For each <th> in your header row inside <thead>, add scope="col".
  2. If any column in your table uses <th> as a row label (first column), add scope="row" to those cells.

Before:

<thead>
<tr>
<th>Rating</th>
<th>Typical Distance</th>
</tr>
</thead>

After:

<thead>
<tr>
<th scope="col">Rating</th>
<th scope="col">Typical Distance</th>
</tr>
</thead>
  1. Save the file. The page looks the same — but the table is now properly accessible.
  • scope="col" on a <th> tells screen readers that this header applies to the column below it.
  • scope="row" on a <th> tells screen readers that this header applies to the row to its right.
  • scope has no visual effect — it only helps assistive technologies understand the table’s structure.
  • Use scope on every <th> element in your tables as standard practice.