~/TechPurAI
~/tutorials/html-from-scratch/tables-for-real-tabular-data
beginner·part 9 of 22·3 min read

Tables: real tabular data, done correctly

Updated Aug 16, 2026HTML

Tables have a real, narrow, correct use in HTML: genuinely tabular data, where rows and columns both carry real meaning. This part builds one — a real subscription plan comparison for Bright Leaf Coffee — the exact kind of content a table is actually meant for.

A real comparison table

html
<table>
  <caption>Compare Bright Leaf Coffee subscription plans</caption>
  <thead>
    <tr>
      <th scope="col">Plan</th>
      <th scope="col">Price</th>
      <th scope="col">Bags per month</th>
      <th scope="col">Free shipping</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Gift Subscription</th>
      <td>$18/mo</td>
      <td>1</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th scope="row">Monthly Subscription</th>
      <td>$16/mo</td>
      <td>1</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th scope="row">Double Bag</th>
      <td>$30/mo</td>
      <td>2</td>
      <td>Yes</td>
    </tr>
  </tbody>
</table>

What each piece is actually doing

Why scope is the detail almost everyone skips

text
Without scope: a screen reader announces each cell's value with no
  indication of which row or column header it belongs to — "$18/mo"
  alone, with no context
With scope: the same cell is announced with its real header context —
  "Gift Subscription, Price: $18/mo"

scope="col" and scope="row" are what let a screen reader correctly associate a data cell with its real header when read out of visual/sequential order — genuinely necessary for a table of any real complexity, and the single most commonly missing piece in tables built without accessibility in mind from the start.

When a table is the wrong choice

html
<!-- wrong: using a table purely to force a two-column visual layout -->
<table>
  <tr>
    <td><img src="/images/logo.svg" alt="Bright Leaf Coffee" /></td>
    <td><nav><a href="/">Home</a></nav></td>
  </tr>
</table>

Tables were commonly misused for page layout in older web design, before CSS layout tools were reliable — using a table purely to force a visual grid, with no real tabular data inside it, is a real, outdated anti-pattern. A screen reader announces that structure as an actual data table, misleadingly implying the header and nav are related tabular data when they're not. Layout is CSS's job (covered later in this series); tables are for real data with genuine rows-and-columns meaning, like the subscription comparison above.

Common mistake

Building a real data table without <th> at all — using <td> for every cell, including the header row. It renders visually similar by default in most browsers, but it's structurally meaningless: nothing in the markup actually identifies which cells are headers, which is exactly the information scope and <th> exist to provide.

Responsive tables: a real, honest limitation

Wide tables with many columns are a genuine, unsolved layout challenge on narrow phone screens — HTML alone doesn't have a built-in mechanism to reflow a table's columns into something narrower. The common real solutions (horizontal scroll on a wrapping container, or restructuring data into cards below a breakpoint) are CSS-layer decisions, covered when this series reaches styling — worth knowing as a real constraint now, even before the solution is covered.

Next: forms — the fundamentals of <form>, input types, and labels, building Bright Leaf Coffee's real newsletter signup.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous8. The real project starts: Bright Leaf Coffee's actual homepagenext →10. Forms fundamentals: form, input types, and labels