HTMLRows & Cells (<tr>, <td>, <th>)

Rows & Cells (<tr>, <td>, <th>)

Every HTML table is built from three elements repeated over and over: <tr> for rows, and <td>/<th> for the cells inside each row. Getting these three right — especially the{' '} scope attribute on <th> — is what separates a merely-visual table from an accessible one.

<tr> — Table Row

<tr> (table row) is a direct wrapper around a set of cells. A table is simply a stack of{' '} <tr> elements, each containing the same number of cells (accounting for any colspan).

HTML
<table>
  <tr>
    <th>Name</th>
    <th>Role</th>
  </tr>
  <tr>
    <td>Ada Lovelace</td>
    <td>Mathematician</td>
  </tr>
</table>
<td> — Table Data Cell

<td> holds a plain data value — the actual content of the table, as opposed to a label describing it. Browsers render <td> with normal-weight, left-aligned text by default.

HTML
<tr>
  <td>Ada Lovelace</td>
  <td>Mathematician</td>
  <td>1815</td>
</tr>
<th> — Table Header Cell

<th> marks a cell as a header — a label that describes an entire row or column of data. Browsers render it bold and centered by default, but the important part is semantic, not visual: assistive technology associates every <td> in that row/column with its <th>.

HTML
<tr>
  <th>Name</th>
  <th>Role</th>
  <th>Born</th>
</tr>
Warning
Do not use <th> just because you want bold, centered text — that's a CSS job (font-weight, text-align). Use <th> only for cells that genuinely act as a header for other cells.
The scope Attribute

scope tells assistive technology exactly what a <th> is a header FOR — an entire column, an entire row, or a group of columns/rows. Without it, a screen reader has to guess based on position, which works for simple tables but fails on complex ones.

scope value

Meaning

col

This header describes every cell in its column

row

This header describes every cell in its row

colgroup

This header describes a group of columns (used with colspan)

rowgroup

This header describes a group of rows (used with rowspan)

HTML
<table>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Role</th>
    <th scope="col">Born</th>
  </tr>
  <tr>
    <th scope="row">Ada Lovelace</th>
    <td>Mathematician</td>
    <td>1815</td>
  </tr>
  <tr>
    <th scope="row">Grace Hopper</th>
    <td>Computer scientist</td>
    <td>1906</td>
  </tr>
</table>
Note
This table has header cells in both directions: the top row (scope="col") labels each column, and the leftmost cell in each data row (scope="row") labels that row. A screen reader announcing the "1906" cell can now say "Born, Grace Hopper, 1906" — both headers, automatically.
Header Cell Association in Practice

When a screen reader user moves focus to a data cell in table navigation mode, it reads the cell's value together with the header(s) that describe it — the column header, and (if scope is set) the row header too.

Text
Screen reader announces when landing on the "1906" cell:
  "Born, column 3.  Grace Hopper, row 3.  1906."
Tip
Always add scope="col" to header rows and scope="row" to header columns, even in simple tables. It costs nothing visually and makes every table properly navigable with a screen reader.
Cells Don't Have to Be Text

<td> and <th> can contain any flow content — links, images, lists, even nested tables (used sparingly). The cell is just a container.

HTML
<tr>
  <th scope="row">Profile</th>
  <td><img src="avatar.jpg" alt="Ada Lovelace portrait" width="40" height="40"></td>
  <td><a href="/people/ada-lovelace">View profile</a></td>
</tr>
Common Mistakes
  • Mismatched cell counts — every <tr> in a table (accounting for colspan) should add up to the same number of columns.

  • Using <th> purely for visual styling instead of semantic headers.

  • Skipping scope on header cells in tables with headers in both directions.

  • Nesting a block element like <div> directly inside <table>/<tr> outside of a <td>/<th> — the browser will silently move or drop it.

Key Takeaways
  1. <tr> is a row; <td> is a plain data cell; <th> is a header cell.

  2. <th> is semantic, not just a bold/centered style — use CSS for pure visual formatting.

  3. scope="col" and scope="row" explicitly associate a header with the cells it describes.

  4. Tables with headers in both directions (row AND column headers) need scope on both to be fully accessible.

  5. Cells can contain any flow content, not just plain text.