HTML Exercise - Tables
In this exercise, we will create an HTML page that holds six different table elements.
Exercise text
Create an HTML page that has the following tables:
- A table with one row of table cells (View the solution)
- A table with multiple rows of table cells (View the solution)
- A table with column headers (View the solution)
- A table with row headers (View the solution)
- A table with row and column headers (View the solution)
- A table with the following sections: (View the solution)
- Table caption -
<caption> - Table header -
<thead> - Table body -
<tbody> - Table footer -
<tfoot>
- Table caption -
Solution
The index.html file with six different tables:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Page Title</title>
</head>
<body>
<h1>Tables Exercise</h1>
<h2>1. A table with one row</h2>
<!-- A table with one row -->
<table>
<tr><!-- Table row -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
</table>
<h2>2. A table with multiple rows</h2>
<!-- A table with multiple rows -->
<table>
<tr><!-- First table row -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
<tr><!-- Second table row -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
<td>Table Cell 2.3</td>
</tr>
</table>
<h2>3. A table with column headers</h2>
<!-- A table with column headers -->
<table>
<tr><!-- A row that holds column headers -->
<th>Column Header 1</th><!-- Column header 1 -->
<th>Column Header 2</th><!-- Column header 2 -->
<th>Column Header 3</th><!-- Column header 3 -->
</tr>
<tr><!-- A row of regular data cells -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
<tr><!-- Another row of regular data cells -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
<td>Table Cell 2.3</td>
</tr>
</table>
<h2>4. A table with row headers</h2>
<!-- A table with row headers -->
<table>
<tr><!-- First table row -->
<th>Row Header 1</th><!-- Row header 1 -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
</tr>
<tr><!-- Second table row -->
<th>Row Header 2</th><!-- Row header 2 -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.1</td>
</tr>
</table>
<h2>5. A table with row and column headers</h2>
<!-- A table with row and column headers -->
<table>
<!-- A row with a blank cell and two column headers -->
<tr>
<td> </td><!-- A blank cell holding a space -->
<th scope="col">Column Header 1</th><!-- Column header -->
<th scope="col">Column Header 2</th><!-- Column header -->
</tr>
<!-- A row with the row header and two regular cells -->
<tr>
<th scope="row">Row Header 1</th><!-- Row header -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
</tr>
<!-- A row with the row header and two regular cells -->
<tr>
<th scope="row">Row Header 2</th><!-- Row header -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
</tr>
</table>
<h2>6. A table with different table sections</h2>
<!-- A table with different table sections -->
<table>
<!-- The caption section -->
<caption>This is the table caption</caption>
<!-- The table heading section -->
<thead>
<tr>
<th scope="col">Column Header 1</th>
<th scope="col">Column Header 2</th>
<th scope="col">Column Header 3</th>
</tr>
</thead>
<!-- The table body section -->
<tbody>
<tr>
<td>Table Cell 1.1.</td>
<td>Table Cell 1.2.</td>
<td>Table Cell 1.3.</td>
</tr>
<tr>
<td>Table Cell 2.1.</td>
<td>Table Cell 2.2.</td>
<td>Table Cell 2.3.</td>
</tr>
</tbody>
<!-- The table footer section -->
<tfoot>
<tr>
<th scope="row" colspan="2">Total:</th>
<td>Some Summary 123</td>
</tr>
</tfoot>
</table>
</body>
</html>
Explanation
Our HTML page has several tables, each with its own set of features and elements. Below is a breakdown of different tables.
1. A table with one row
The first table in our page is a simple table element with one row of data cells:
<!-- A table with one row -->
<table>
<tr><!-- Table row -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
</table>
The table is represented through the <table> element, the row is represented through the <tr> element and individual table cells are represented through the <td> element. This table has a single row that holds three data cells. We say it has "one row and three columns".
2. A table with multiple rows
The next table holds two rows of data cells:
<!-- A table with multiple rows -->
<table>
<tr><!-- First table row -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
<tr><!-- Second table row -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
<td>Table Cell 2.3</td>
</tr>
</table>
We have two table rows of data, represented by two instances of the <tr> element. Each row, in our case, holds three data cells, represented by multiple <td> elements. We can also say our table is "2 by 3". It has two rows and three columns in total.
3. A table with column headers
The following table in our HTML page:
<!-- A table with column headers -->
<table>
<tr><!-- A row that holds column headers -->
<th>Column header 1</th><!-- Column header 1 -->
<th>Column header 2</th><!-- Column header 2 -->
<th>Column header 3</th><!-- Column header 3 -->
</tr>
<tr><!-- A row of regular data cells -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
<td>Table Cell 1.3</td>
</tr>
<tr><!-- Another row of regular data cells -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
<td>Table Cell 2.3</td>
</tr>
</table>
Has three column headers (represented by three header cells). These table header cells are positioned in the first row. The remaining two rows hold regular data cells.
If you want to explicitly state the relationship between header and data cells, use the scope attribute on header cells and set it to the value of col:
<tr><!-- A row that holds column headers -->
<th scope="col">Column header 1</th><!-- Column header 1 -->
<th scope="col">Column header 2</th><!-- Column header 2 -->
<th scope="col">Column header 3</th><!-- Column header 3 -->
</tr>
The scope attribute is not needed, as the relationship is implied. But its presence explicitly specifies the relationship and improves accessibility when read by screen reader software.
4. A table with row headers
The following table:
<!-- A table with row headers -->
<table>
<tr><!-- First table row -->
<th>Row header 1</th><!-- Row header 1 -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
</tr>
<tr><!-- Second table row -->
<th>Row header 2</th><!-- Row header 2 -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.1</td>
</tr>
</table>
Defines a table with two table rows, each holding a table row cell (<th>) and several, regular data cells (<td>). There is one row header cells (<th>) per table row. A row header cell is the first cell in each row, followed by one or more regular data cells (<td>), depending on how many columns we want.
To explicitly state that these th cells are indeed table row cells, we can set their scope attribute to the value of row. We can rewrite the above code as:
<!-- A table with row headers -->
<table>
<tr><!-- First table row -->
<th scope="row">Row header 1</th><!-- Row header 1 -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
</tr>
<tr><!-- Second table row -->
<th scope="row">Row header 2</th><!-- Row header 2 -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.1</td>
</tr>
</table>
Whether or not to use the scope attribute is ultimately up to us, because the table heading role/relationship is implied. If we want to improve accessibility on our page, we indeed should use it.
5. A table with both row and column headers
The following table on our page:
<!-- A table with row and column headers -->
<table>
<!-- A row with a blank cell and two column headers -->
<tr>
<td> </td><!-- A blank cell holding a space -->
<th scope="col">Column Header 1</th><!-- Column header -->
<th scope="col">Column Header 2</th><!-- Column header -->
</tr>
<!-- A row with one row header and two regular cells -->
<tr>
<th scope="row">Row Header 1</th><!-- Row header -->
<td>Table Cell 1.1</td>
<td>Table Cell 1.2</td>
</tr>
<!-- A row with one row header and two regular cells -->
<tr>
<th scope="row">Row Header 2</th><!-- Row header -->
<td>Table Cell 2.1</td>
<td>Table Cell 2.2</td>
</tr>
</table>
Represents a table with both column and row headers. The first table row contains only column header cells (plus one empty top-left cell). The remaining rows contain row headers and regular data cells.
Both column and row header cells have the scope attribute which clearly defines what the header cell represents. The cell is either a column header or a row header.
6. A table with different table sections
Finally, we have an HTML5-style table with different sections:
<!-- A table with different table sections -->
<table>
<!-- Caption section -->
<caption>This is the table caption</caption>
<!-- Table heading section -->
<thead>
<tr>
<th scope="col">Column Header 1</th>
<th scope="col">Column Header 2</th>
<th scope="col">Column Header 3</th>
</tr>
</thead>
<!-- Table body section -->
<tbody>
<tr>
<td>Table Cell 1.1.</td>
<td>Table Cell 1.2.</td>
<td>Table Cell 1.3.</td>
</tr>
<tr>
<td>Table Cell 2.1.</td>
<td>Table Cell 2.2.</td>
<td>Table Cell 2.3.</td>
</tr>
</tbody>
<!-- The table footer section -->
<tfoot>
<tr>
<th scope="row" colspan="2">Total:</td>
<td>Some Summary 123</td>
</tr>
</tfoot>
</table>
This table starts with a <caption> section that holds a short caption, representing the entire table.
<caption>This is the table caption</caption>
The following section is the <thead> table header section which usually holds one or more rows of column header cells.
<thead>
<tr>
<th scope="col">Column Header 1</th>
<th scope="col">Column Header 2</th>
<th scope="col">Column Header 3</th>
</tr>
</thead>
Next, we have a table body <tbody> section that usually contains multiple rows of data cells (and row header cells, if needed).
<tbody>
<tr>
<td>Table Cell 1.1.</td>
<td>Table Cell 1.2.</td>
<td>Table Cell 1.3.</td>
</tr>
<tr>
<td>Table Cell 2.1.</td>
<td>Table Cell 2.2.</td>
<td>Table Cell 2.3.</td>
</tr>
</tbody>
Finally, we have a table footer <tfoot> section, which usually holds a single row of cells, representing the column summary, average values and similar.
<tfoot>
<tr>
<th scope="row" colspan="2">Total:</td>
<td>Some Summary 123</td>
</tr>
</tfoot>
The row in this section usually contains a row header cell that spans several columns using the colspan="number-of-columns" attribute.
Summary
In this exercise, we created several HTML tables, starting with a simple one-row table and then moving on to tables with column headers, row headers, and different table sections. For more detailed information about the <table> element, you can check out our HTML tables tutorial.