Complete HTML Course Module 6: Intermediate: HTML Tables

How to Create a Table in HTML

  • Beginner
  • Lesson 6.1
  • 4 min read
  • 28 of 69 in the course

In short

To create a table in HTML, you use table, tr, th and td, plus caption, thead, tbody, tfoot and scope to make the data clear and accessible. When should you use an HTML table? A table shows tabular data: information that has rows and columns, like a spreadsheet.

To create a table in HTML, you use table, tr, th and td, plus caption, thead, tbody, tfoot and scope to make the data clear and accessible.

When should you use an HTML table?

A table shows tabular data: information that has rows and columns, like a spreadsheet. Think of a train timetable, a price list or a sports league. If it makes sense to read the data both across and down, a table is the right tool.

Tables are for data only, not for page layout. You will learn more about that in the next lesson.

The basic table elements: table, tr, th and td

An HTML table is built from a few simple elements:

  • <table> wraps the whole table.
  • <tr> is a table row.
  • <th> is a table header cell, a title for a row or column. Browsers show it in bold and centred by default.
  • <td> is a table data cell, a normal cell with data.

You build the table row by row. Each <tr> holds its cells from left to right.

<table>
  <tr>
    <th>Plan</th>
    <th>Price per month</th>
    <th>Storage</th>
  </tr>
  <tr>
    <td>Basic</td>
    <td>£4</td>
    <td>50 GB</td>
  </tr>
  <tr>
    <td>Pro</td>
    <td>£9</td>
    <td>500 GB</td>
  </tr>
</table>

You will see a small grid with three columns. The first row is bold because it uses <th>. There are no borders yet; you add those with CSS. To see the grid while you practise, you can add a quick CSS rule later like border: 1px solid on cells.

Common mistake: Putting text directly inside <tr> or <table>. Text must always go inside a <td> or <th> cell, or the browser will move it outside the table.

Adding a caption, thead, tbody and tfoot

A <caption> is the title of the table. It must be the first thing inside <table>. It helps everyone, especially screen reader users, understand what the table is about before they read it.

You can also split the table into three groups of rows:

  • <thead> holds the header row or rows.
  • <tbody> holds the main data rows.
  • <tfoot> holds summary rows, like totals.

These groups make the code easier to read, help screen readers, and give you easy hooks for CSS. When a long table is printed, browsers can repeat the <thead> on each page.

Using scope to connect headers to cells

The scope attribute on a <th> says which cells it is the header for:

  • scope="col" means "I am the header for this column".
  • scope="row" means "I am the header for this row".

With scope, a screen reader can read a cell as "Tuesday, 10:00, Yoga" instead of just "Yoga". It is a small addition that makes a big difference.

Here is a full, real-world class timetable for a gym:

<table>
  <caption>Bright Fitness weekly class timetable</caption>
  <thead>
    <tr>
      <th scope="col">Time</th>
      <th scope="col">Monday</th>
      <th scope="col">Tuesday</th>
      <th scope="col">Wednesday</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">08:00</th>
      <td>Spinning</td>
      <td>Yoga</td>
      <td>Spinning</td>
    </tr>
    <tr>
      <th scope="row">12:30</th>
      <td>Pilates</td>
      <td>Strength</td>
      <td>Pilates</td>
    </tr>
    <tr>
      <th scope="row">18:00</th>
      <td>Boxing</td>
      <td>Spinning</td>
      <td>Yoga</td>
    </tr>
  </tbody>
</table>

The caption appears above the table. The days across the top are column headers, and the times down the left side are row headers. Both are bold. Every class cell is now linked to a time and a day.

And here is a price table with a total in the footer:

<table>
  <caption>Your order</caption>
  <thead>
    <tr>
      <th scope="col">Item</th>
      <th scope="col">Quantity</th>
      <th scope="col">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Coffee beans (500 g)</th>
      <td>2</td>
      <td>£16.00</td>
    </tr>
    <tr>
      <th scope="row">Ceramic mug</th>
      <td>1</td>
      <td>£12.00</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th scope="row">Total</th>
      <td></td>
      <td>£28.00</td>
    </tr>
  </tfoot>
</table>

This shows an order summary with the total row at the bottom. The empty <td> keeps the columns lined up. In the next lesson you will learn how to merge cells so you don't need empty ones.

Tip: Always add a <caption> and use <th> with scope for headers. It takes ten extra seconds and makes your table accessible. See MDN: The table element for more details.

Practice exercise

Create a table that shows the opening hours of a library for each day of the week. Use a <caption>, a <thead> with "Day", "Opens" and "Closes", and a <tbody> with seven rows. Make each day name a row header.

Hint: Day names go in <th scope="row">, and the column titles go in <th scope="col">.

Key takeaways

  • Use tables only for data with rows and columns.
  • Build tables with <table>, <tr>, <th> and <td>.
  • Add a <caption> and group rows with <thead>, <tbody> and <tfoot>.
  • Use scope="col" and scope="row" on header cells so screen readers can connect data to headers.