🚀 New batches open: Advanced Excel • Power BI • SQL • AI for Analytics — Book a free demo

Day 4 — Tables that are actually tables

Tables are for data. If you are using one to position things on a page, stop - that is Day 9.

The smallest table

<table>
  <tr>
    <td>Excel</td>
    <td>6 weeks</td>
  </tr>
  <tr>
    <td>SQL</td>
    <td>4 weeks</td>
  </tr>
</table>

tr is a row, td is a cell. Rows go down, cells go across inside them.

Headers, and the attribute nobody uses

<th> is a header cell. Add scope and a screen reader can announce "Duration: 6 weeks" instead of reading a wall of disconnected numbers.

<table>
  <caption>Course durations, 2026 batches</caption>
  <thead>
    <tr>
      <th scope="col">Course</th>
      <th scope="col">Duration</th>
      <th scope="col">Fee</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Advanced Excel</th>
      <td>6 weeks</td>
      <td>12,000</td>
    </tr>
    <tr>
      <th scope="row">Power BI</th>
      <td>5 weeks</td>
      <td>14,000</td>
    </tr>
  </tbody>
</table>
PartJob
<caption>The table’s title. Goes first, inside the table.
<thead>The header row or rows.
<tbody>The data.
<tfoot>Totals.
scope="col"This th labels the column below it.
scope="row"This th labels the row beside it.

Cells that span

<table>
  <thead>
    <tr>
      <th scope="col">Course</th>
      <th scope="col" colspan="2">Batches</th>
    </tr>
    <tr>
      <th scope="col"></th>
      <th scope="col">Weekday</th>
      <th scope="col">Weekend</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Excel</th>
      <td>7am</td>
      <td>10am</td>
    </tr>
    <tr>
      <th scope="row">SQL</th>
      <td colspan="2">On request</td>
    </tr>
  </tbody>
</table>
Count your cells Every row must add up to the same number of columns, counting a colspan="2" as two. Get it wrong and the table goes crooked with no error message anywhere. When a table looks broken, count the cells in each row first.

A total row

<table>
  <caption>Enrolments this quarter</caption>
  <thead>
    <tr><th scope="col">Month</th><th scope="col">Students</th></tr>
  </thead>
  <tbody>
    <tr><th scope="row">January</th><td>42</td></tr>
    <tr><th scope="row">February</th><td>38</td></tr>
    <tr><th scope="row">March</th><td>51</td></tr>
  </tbody>
  <tfoot>
    <tr><th scope="row">Total</th><td>131</td></tr>
  </tfoot>
</table>

When not to use a table

The test Would this make sense as a spreadsheet, with meaningful rows and columns? Then it is a table.
Are you only using it to get two things side by side? Then it is not - that is a layout job, and Flexbox on Day 9 does it properly. Table layouts collapse badly on phones and confuse screen readers, which announce "table with 3 rows" before reading your navigation menu.

Tables on a phone

A wide table on a 360px screen either squashes into unreadable columns or pushes the whole page sideways. The usual fix is to let the table scroll inside its own box.

<div style="overflow-x: auto">
  <table>
    <thead>
      <tr>
        <th scope="col">Course</th><th scope="col">Duration</th>
        <th scope="col">Fee</th><th scope="col">Batch</th>
        <th scope="col">Trainer</th><th scope="col">Mode</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Advanced Excel</td><td>6 weeks</td><td>12,000</td>
        <td>Weekday</td><td>Anita</td><td>Classroom</td>
      </tr>
    </tbody>
  </table>
</div>

The wrapper scrolls sideways instead of the whole page. You will meet this pattern again on Day 10.

Try these yourself

  1. Build a table of five courses with columns for duration and fee, using thead and tbody.
  2. Add a caption and scope attributes to every header cell.
  3. Add a tfoot row with the total fee.
  4. Deliberately give one row too few cells, run it, and see what the table does.
  5. Give one example of data that belongs in a table and one that does not.