Tables

Tables are a feature in HTML that look harder than they really are. All a table really is is a long nest of tags defining the rows and individual cells of the table. You can think of them best as trees, starting from the table itself and getting more granular until you're at the individual cell level.

Special HTML attributes also exist for table captions and making a cell span any number of rows and columns. While tables are excellent for displaying data, they're not recommended for layouts—I'll demonstrate that towards the end of the article.

Tables, rows, cells

To make a table, start with the <table>...</table> tags. These tags alone won't display much; you'll need more tags, one for each row and one for each cell in each row.

Define your rows like so.

<table>
	<tr>
	</tr>
	<tr>
	</tr>
	<tr>
	</tr>
</table>
	

Then, nestled inside each <tr>, define each cell using the <td>...</td> tags.

<table>
	<tr>
		<td>No.</td>
		<td>Title</td>
		<td>Artist</td>
		<td>Length</td>
	</tr>
	<tr>
		<td>1.</td>
		<td>"Superdeformed"</td>
		<td>Matthew Sweet</td>
		<td>3:58</td>
	</tr>
	<tr>
		<td>2.</td>
		<td>"For All to See"</td>
		<td>Buffalo Tom</td>
		<td>3:36</td>
	</tr>
	<tr>
		<td>3.</td>
		<td>"Sexual Healing"</td>
		<td>Soul Asylum</td>
		<td>4:45</td>
	</tr>
	<tr>
		<td>4.</td>
		<td>"Take a Walk"</td>
		<td>Urge Overkill</td>
		<td>4:39</td>
	</tr>
	<tr>
		<td>5.</td>
		<td>"All Your Jeans Were Too Tight"</td>
		<td>American Music Club</td>
		<td>3:33</td>
	</tr>
</table>
	

(No, there's no way to make tables any shorter.)

From that, you should get something like the following:

No. Title Artist Length
1. "Superdeformed" Matthew Sweet 3:58
2. "For All to See" Buffalo Tom 3:36
3. "Sexual Healing" Soul Asylum 4:45
4. "Take a Walk" Urge Overkill 4:39
5. "All Your Jeans Were Too Tight" American Music Club 3:33

Sometimes, you need to have a cell that actually takes up multiple. This is where the rowspan and colspan attributes come into play. Both attributes take a number value for how many rows down and how many columns across the cell should take up in the table. You should apply them to the <td> tags in your table only.

Table headers and captions

It's a little basic, don't you think? Let's make this a little easier to read with two important tags, <th>...</th> (for table headers) and <caption>...</caption> (for a table caption).

Table headers work just like table data cells, being sandwiched in between the table row tags like normal. Semantically, header cells define the purpose of each row and column in the table.

<tr>
	<th>No.</th>
	<th>Title</th>
	<th>Artist</th>
	<th>Length</th>
</tr>

Meanwhile, the <caption>...</caption> goes inside the <table>...</table> tags, to associate it only with that table.

<caption><cite>No Alternative</cite> tracklist, Side A</caption>

Adding these to our existing table:

No Alternative tracklist, Side A
No. Title Artist Length
1. "Superdeformed" Matthew Sweet 3:58
2. "For All to See" Buffalo Tom 3:36
3. "Sexual Healing" Soul Asylum 4:45
4. "Take a Walk" Urge Overkill 4:39
5. "All Your Jeans Were Too Tight" American Music Club 3:33

<thead>, <tbody>, <tfoot>

While our tables so far haven't had much in the way of semantics, three tags can be used to group rows in a table to define their intended purpose. <thead>, <tbody>, <tfoot> are optional semantic tags that define the header of the table, the body of the table, and the footer of the table, respectively. This is useful for styling purposes as well.

To use any of the semantic table tags, simply wrap the rows you'd like to include in the table header, body, or footer in their respective tags. Applied to my example table (with some light styling included):

<table>
	<caption><cite>No Alternative</cite> tracklist, Side A</caption>
	<thead>
		<tr>
			<th>No.</th>
			<th>Title</th>
			<th>Artist</th>
			<th>Length</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>1.</td>
			<td>"Superdeformed"</td>
			<td>Matthew Sweet</td>
			<td>3:58</td>
		</tr>
		<tr>
			<td>2.</td>
			<td>"For All to See"</td>
			<td>Buffalo Tom</td>
			<td>3:36</td>
		</tr>
		<tr>
			<td>3.</td>
			<td>"Sexual Healing"</td>
			<td>Soul Asylum</td>
			<td>4:45</td>
		</tr>
		<tr>
			<td>4.</td>
			<td>"Take a Walk"</td>
			<td>Urge Overkill</td>
			<td>4:39</td>
		</tr>
		<tr>
			<td>5.</td>
			<td>"All Your Jeans Were Too Tight"</td>
			<td>American Music Club</td>
			<td>3:33</td>
		</tr>
	</tbody>
</table>
No Alternative tracklist, Side A
No. Title Artist Length
1. "Superdeformed" Matthew Sweet 3:58
2. "For All to See" Buffalo Tom 3:36
3. "Sexual Healing" Soul Asylum 4:45
4. "Take a Walk" Urge Overkill 4:39
5. "All Your Jeans Were Too Tight" American Music Club 3:33

Using <table> for layout (and why you shouldn't)

You might be thinking that tables are a boon for layouts. After all, you get total control over the structure of your page and everything remains nicely organized and lined up.

There's a good reason why you shouldn't do that. Like most things with HTML, it comes down to semantics.

Remember that HTML is only for representing data, not of determining how that data should look. Tables excel at representing a set of data such as the album tracklisting I've been using as an example here, and screen readers and other accessibility devices are optimized to break this data down and represent it however it sees fit.

Using tables for general layouts, however, confuses these devices, as they expect a table to represent data, not layout information. More broadly, your site will be harder to use on mobile devices and non-visual clients, such as Lynx.

Mixing layout and data is rarely a good idea; this is why we maintain separated stylesheets, after all. Table layouts cause the information on the page to become inseparable with the way it's meant to look. This makes it harder to maintain if you decide to redesign your site layout.

The alternative, instead, is to use tables only for representing data and using CSS for laying out and styling your page. In particular, CSS grid is a layout engine built for defining the rows and columns of a page and slotting elements into that grid, much like a table. It's far faster, far easier to maintain, and more flexible than trying to use a table to lay out your site.

Summary:

  1. Tables are essentially nests of tags—first the table itself, then the table rows, then any table headers and table cells inside of those.
  2. Cells can span as many rows and columns as you'd like them to, using the rowspan and colspan attributes. By default, each cell spans one space.
  3. <thead>, <tbody>, <tfoot> are optional semantic tags useful for further defining the function of cells in a table (and styling, of course).
  4. Tables should not be used for layouts: aside from being messier to maintain, they're less accessible for screen readers and non-visual clients. Use something like CSS grid instead.

Further reading