Tables and figures
Tables for tabular data, figures for illustrations. Two structures, two jobs, frequently confused.
For a few years in the 1990s, web designers used HTML tables to lay out everything — navigation bars, sidebars, even the spaces between paragraphs. That was a mistake the field has since corrected. Tables are for tabular data — rows and columns where each cell genuinely belongs to a row and a column. Figures are for illustrations — an image, diagram, or code block paired with a caption. This lesson sorts out which is which.
Tables for tabular data
A <table> is the right element when the content has a real grid structure. Train timetables, a price comparison, a roster of players with their stats, last month's sales by region — anything where reading across a row and reading down a column both produce meaningful relationships.
A simple price list is a good first example.
<table>
<thead>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Loaf of sourdough</td>
<td>$8</td>
</tr>
<tr>
<td>Croissant</td>
<td>$4</td>
</tr>
</tbody>
</table>Even without seeing the rendered output, the structure tells you what is going on: a header row with two column titles, and two data rows with item-and-price pairs. A screen reader can announce that as "Item, $8" and "Croissant, $4" by pairing each cell with its column header. That is the magic of tables when used right.
What makes this tabular is that each cell belongs to both a row and a column simultaneously. "$4" is in the "Croissant" row and the "Price" column. Strip away either dimension and the cell loses its meaning. If your content does not have that property, it is not tabular and a table is the wrong tool.
If you are reaching for a table to put two things side by side on the page (like a sidebar next to your content), stop. That is a layout job for CSS — flexbox or grid. Using a table for visual layout breaks accessibility and makes the page harder to maintain.
Anatomy of a table
The price list above used five element types. Here is what each one is for:
<table>wraps the whole grid.<tr>stands for table row. It wraps one row of cells.<th>stands for table header cell — a cell that labels a column or row. Browsers bold it by default. Screen readers use it to label the data cells underneath.<td>stands for table data cell — a regular cell holding one piece of data.<thead>and<tbody>group the header rows and the body rows. They are optional but recommended; they make the structure explicit and let browsers do useful things like keep the header visible when the table scrolls.
A useful picture: a table is like a spreadsheet. <table> is the sheet, <tr> is one row, <th> is a column or row label (bold by default), and <td> is a regular cell. <thead> is the locked header row at the top.
There is also <caption>, which gives the table a title that screen readers announce up front:
<table> <caption>Bakery prices, April 2026</caption> <thead> <tr><th>Item</th><th>Price</th></tr> </thead> ... </table>
Put the caption right after the opening <table> tag. It is the first thing the visitor (or screen reader) reads, so it should describe what the table is about in one short phrase.
Figures and captions
A <figure> is a self-contained illustration with a caption. The illustration can be an image, a diagram, a code block, a quote, or a chart — anything you might point at and say "see figure 4". The caption goes inside a <figcaption> element.
<figure> <img src="cake-cross-section.jpg" alt="Cross-section of a layer cake showing four sponge layers separated by buttercream."> <figcaption>The classic four-layer Victoria sponge.</figcaption> </figure>
The wrapper does two things. First, it tells screen readers and search engines "this image and this caption belong together" — they are read as a unit, not as two unrelated bits of content. Second, it lets you move the whole illustration around (later in the page, into a sidebar, anywhere) without splitting it from its caption.
The <figcaption> can come before or after the image. Most designs put it underneath, but a caption above the image is fine when that reads better.
A figure does not have to be an image. A code block paired with a caption is also a figure — many technical books use figures this way:
<figure>
<pre><code>function greet(name) {
return "Hello, " + name;
}</code></pre>
<figcaption>A function that returns a greeting.</figcaption>
</figure>Here the "illustration" is the code, and the caption explains what it does. Treat any standalone illustration with an explanation underneath as a candidate for <figure>.
If the image is part of the prose ("the screenshot below shows the login form") and removing it would leave a hole in the sentence, you do not need <figure> — a plain <img> is enough. <figure> earns its place when the illustration could be moved without breaking the surrounding text.
Picking the right one
Tables and figures get confused because both put a labelled rectangle on the page. The way to tell them apart is to look at what the labels are doing:
- A table has rows and columns of related data. The "labels" (
<th>) describe what each cell means within a grid. - A figure is one illustration with one caption. The caption describes the whole illustration in a sentence or two.
A pricing chart with three plans across the top and ten features down the side is a table. A photograph of the team with a caption underneath is a figure. A diagram showing the request-response cycle, with one explanatory line of text, is a figure.
If the content has a grid structure, use <table>. If it has a one-illustration-plus-caption structure, use <figure>. If it is neither — just a regular image inside flowing prose — use a plain <img> with an alt attribute.
<table> to put a sidebar of links next to the article body. The page renders fine on desktop. What is the strongest reason to push back?