CodeLair website tutorials, articles & scripts

Tables in HTML

Published: 14 February 2007   •   Tags: html, css

This tutorial will show you how to create HTML tables for displaying data in an organized fashion, including some neat CSS styling tricks.

Tables provide a convenient method of displaying and arranging data and other content. No doubt you are familiar with tables from other contexts - they are commonplace in word processing documents, and spreadsheets are in fact one giant table. Tables can be quite easily constructed in WYSIWYG HTML editors such as Dreamweaver or FrontPage, but for a number of reasons it really is worth knowing how the HTML code behind them fits together.

The subject of tables is actually quite a large and complex one, hence we will summarize only the most important and useful aspects here. If you are familiar with the W3C specs you can take a look at the tables section to find additional features and more in-depth descriptions.

Note: many of the attributes shown in this article, such as width or cellpadding, are now deprecated and have been superceded by CSS alternatives. See the final part of the article for examples.

Our first HTML table #

We start with the most simple table. Tables are signified, unsurprisingly, with the TABLE tag. Inside this, a table is split into rows (TR tag) and cells (TD tag). At the basic level, each row should have the same number of cells. Hence the code for a simple table could look like the following. We have two rows, each row holding two columns.

<table>
<tr>
<td>Row 1, Cell 1</td>
<td>Row 1, Cell 2</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<td>Row 2, Cell 2</td>
</tr>
</table>

View Demo

A better-looking table #

Okay, so that table didn’t look like much, did it? Just a bunch of text. Let’s examine the attributes of the TABLE tag:

  • width: the width of the tables, either in pixels or a percentage of the available space
  • border: defines a border for the table and cells, in pixels
  • cellspacing: the amount of space between each cell, in pixels
  • cellpadding: the amount of space between a cell’s content and its border, in pixels

Here is an example using these attributes; the code is basically the same as the previous example:

<table width="300" border="1" cellspacing="2" cellpadding="5">
...
</table>

View Demo

Cell alignment #

The default alignment of table cells is vertically in the middle of the cell; if one cell on a row creates a line break the text in the other rows will move down. Horizontally, data cells are aligned to the left and header cells to the center. The alignments can be changed with the align and valign attributes of the TH/TD tags; their exact meaning is shown in the demo.

  • align: left, center, right or justify
  • valign: top, middle, bottom or baseline

View Demo

Header cells #

Normally, when we want to use a table, we have some kind of data to put in it. The TH element lets us ‘label’ that data; we use it in place of the TD tag. This example uses a selection of data from imdb.com’s top 250 list. Position, Film, Year and Rating are the labels; the rest of the table is the data.

View Demo

This can be recreated with the following code:

<table border="1" cellspacing="0" cellpadding="3">
<tr>
<th>Position</th>
<th>Film</th>
<th>Year</th>
<th>Rating</th>
</tr>
<tr>
<td>1</td>
<td>The Godfather</td>
<td>1972</td>
<td align="right">9.1</td>
</tr>
<tr>
<td>2</td>
<td>The Shawshank Redemption</td>
<td>1994</td>
<td align="right">9.1</td>
</tr>
<tr>
<td>3</td>
<td>The Godfather: Part II</td>
<td>1974</td>
<td align="right">8.9</td>
</tr>
</table>

The main advantage to using TH cells over TD cells is that you can control the attributes for each separately - for example, use CSS to set a different background color for heading cells. It also helps accessibility: text-to-speech programs can choose to read the heading aloud before every single data cell (to avoid confusion).

Row grouping #

The THEAD, TFOOT and TBODY elements provide a convenient way to group rows of a table, intended to specify groups header rows, footer rows and data rows respectively. They are most useful for the printing of long documents: each page will typically contain the header and footer information, thus improving readability. Furthermore, since there can be multiple TBODY sections in a table, it is useful for partitioning the table and styling different parts. If used, THEAD and TFOOT must come before TBODY.

We use a similar example to the previous section, but splitting the table up into a header row, footer row with source information, body section for the top 3 films, and a body section for the remaining films.

<table border="1" cellspacing="0" cellpadding="3">
<thead>
<tr>
<th>Position</th>
<th>Film</th>
<th>Year</th>
<th>Rating</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="4">Data provided by imdb.com</td>
</tr>
</tfoot>
<tbody bgcolor="lightyellow">
<tr>
<td>1</td>
<td>The Godfather</td>
<td>1972</td>
<td align="right">9.1</td>
</tr>
<tr>
<td>2</td>
<td>The Shawshank Redemption</td>
<td>1994</td>
<td align="right">9.1</td>
</tr>
<tr>
<td>3</td>
<td>The Godfather: Part II</td>
<td>1974</td>
<td align="right">8.9</td>
</tr>
</tbody>
<tbody>
<tr>
<td>4</td>
<td>The Lord of the Rings: The Return of the King</td>
<td>2003</td>
<td align="right">8.8</td>
</tr>
[ ... rest of the data rows here ... ]
</tbody>
</table>

View Demo

Column grouping #

Similarly, groups of columns can be specified using the COLGROUP element. Here a standard width can be set for each of the columns in the group, or each column can be specified individually with the ‘sub-element’ COL. The number of columns in each group can be specified with the span attribute (default is 1). Column groups must be defined before any table cells. Here are a few examples…

Single group of 5 columns, each with the same width:

<colgroup width="20" span="5"></colgroup>

Single group of 5 columns, with different widths:

<colgroup>
<col width="10">
<col width="20">
<col width="20">
<col width="20">
<col width="35">
</colgroup>

The same layout but using the span attribute:

<colgroup>
<col width="10">
<col width="20" span="3">
<col width="35">
</colgroup>

Similar example but splitting the columns into three groups:

<colgroup width="10"></colgroup>
<colgroup width="20" span="3"></colgroup>
<colgroup width="35"></colgroup>

Full table example:

<table border="1" cellspacing="0" cellpadding="3">
<colgroup>
<col width="10%" span="4">
<col width="60%">
</colgroup>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5 (long)</th>
</tr>
<tr>
<td>Data 1,1</td>
<td>Data 1,2</td>
<td>Data 1,3</td>
<td>Data 1,4</td>
<td>Data 1,5 - longer column</td>
</tr>
</table>

Merging cells #

In many cases when defining tables, you may find yourself with multiple identical cells. In large tables this could decrease readability, but if there was only one instance of a value displayed it would improve matters.

In the cell alignment example, there were heading cells along the top and left of the table, representing the values of the align and valign attributes respectively. I also added a sort of label to each set attributes in a single cell above and to the left of them. These cells span multiple columns or rows. The colspan and rowspan attributes can be used with the TH and TD elements to merge certain cells together.

We will start with some simple examples, and a reference table of 9 numbers:

<table border="1" cellpadding="20" cellspacing="0">
<tr> <td>1</td> <td>2</td> <td>3</td> </tr>
<tr> <td>4</td> <td>5</td> <td>6</td> </tr>
<tr> <td>7</td> <td>8</td> <td>9</td> </tr>
</table>

View Reference

Column spanning #

To merge cells in the same row we change the code to something like this (note the colspan="2" attribute):

<table border="1" cellpadding="20" cellspacing="0">
<tr>
<td>1</td> <td>2</td> <td>3</td>
</tr>
<tr>
<td colspan="2">4,5</td> <td>6</td>
</tr>
<tr>
<td>7</td> <td>8</td> <td>9</td>
</tr>
</table>

The total number of columns must be the same in each row. In this example, the first and third rows have three basic cells each; and the second row has two cells, with the first stretched across columns. If the span was 3 instead of 2, it would create 4 columns in the second row, so we would need to remove the cell containing 6.

View Demo

Row spanning #

To merge cells in the same column, we change the reference code to something resembling:

<table border="1" cellpadding="20" cellspacing="0">
<tr>
<td>1</td> <td rowspan="2">2,5</td> <td>3</td>
</tr>
<tr>
<td>4</td> <td>6</td>
</tr>
<tr>
<td>7</td> <td>8</td> <td>9</td>
</tr>
</table>

This one is quite tricky to comprehend, because it looks like each row has a different number of columns. The thing to note here is that a column in one row can be set in a row above it. In this example, the second column of the first row is set to ‘spill over’ into the second row. Because of this, a second column cannot be defined in the second row, which means that when we put two data cells, they define the first and third columns of the row.

View Demo

To help us better understand row spanning, lets look at another example:

<table border="1" cellpadding="3" cellspacing="0">
<tr>
<td>1</td> <td rowspan="3">2,5,8</td> <td>3</td>
</tr>
<tr>
<td>4</td> <td rowspan="2">6,9</td>
</tr>
<tr>
<td>7</td>
</tr>
</table>

View Demo

Three cells in the middle column have been merged, as have the last two cells in the third column. The first row has three cells, the second of which sets a rowspan of 3. Therefore the second and third rows must have two or fewer cells, and the two cells in the second row must define the first and third columns. The third cell in this row has a rowspan of 2, which means that the next row must have one less cell, leaving only one cell defined in that row.

As a final learning exercise, take a look at the alignment example again, this time paying attention to the spanning of the cells. Use the “View source” option of your browser to look at the code and discover which parts of the code control which parts of the table.

Styling tables with CSS #

This part of the tutorial deals with various methods to style tables. All the attributes of the table elements can be represented with CSS, for the most part straightforwardly. Attributes such as width, height, border, cellpadding, align and valign cross over to width, height, border-width, padding, text-align and vertical-align respectively.

The best thing about using CSS is that it gives you further control over the table than you get with the standard attributes, including border styles and coloring. This CSS sets some default attributes for every table in your document:

table {
border: 1px solid black;
background-color: yellow;
}

This applies a black border and yellow background color to the table.

View Demo

If we wish to apply a style to every cell in the table, we can do the following:

table {
border: 1px solid black;
background-color: yellow;
}
th, td {
border: 1px solid red;
background-color: white;
padding: 5px;
}

This applies a black border and yellow background color to the table, and red border with white background color to the individual cells.

View Demo

There is a problem with this method. If your design is made out of tables, then these attribute will apply to those tables, as well as whatever data tables you may have. If we only want to apply these attributes to a few tables, we can use the nested tags feature of CSS, along with our own class definition:

table {
border: 1px solid black;
}
table th {
border: 0;
}
table td {
border: 1px solid black;
}
table.data {
border: 1px solid black;
background-color: yellow;
}
table.data th, table.data td {
border: 1px solid red;
background-color: white;
padding: 3px;
}

We start by setting some default styles for the table and its cells. Although TH and TD should never appear outside of a TABLE tag, we list them as nested here for convenience and consistency. After this we define a class “data”, which applies to the TABLE element. This time we must use nesting so that the cells are only white when they are in a table of class “data”.

View Demo

Note the default cell spacing on each of these tables. The CSS property border-spacing, when applied to the TABLE element, should let us control that. Unfortunately, Internet Explorer 6 does not support it, rendering it pretty useless for the foreseeable future.

There is another related attribute that may help if you want to remove all cell spacing in a table: border-collapse. This is slightly different to setting the cell spacing to zero: with this set to collapse, the borders on the table and each table cell merge - for example, if the border of the cells is set to 1, this will result in an overall border of 1, rather than 2 as is the default. If that did not make sense, here is an example to make it clearer:

table {
border: 1px solid black;
}
table th, table td {
border: 1px solid black;
}
table.data {
border-collapse: collapse;
}
table.data th {
background-color: #f0f0f0;
}
table.data th, table.data td {
padding: 5px;
border: 1px solid #c0c0c0;
}

View Demo

That’s it for now! #

You should now be able to create tables without too much heartache. If you’re trying to make a large or complex table, it is worth planning it carefully in advance, making note of exactly how many columns and rows you need, the headers and where cells span multiple rows.

Personally, I find using Dreamweaver or FrontPage is the quickest way of constructing a table, though they often generate unnecessary or invalid HTML code. It is always worth checking the code produced and modifying it where necessary. Furthermore, it is definitely worth exploring the CSS avenue further; in the long run it will save you a lot of time.