HTML basics · 6 / 8
lesson 6

Tables and figures

Tables for tabular data, figures for illustrations. Two structures, two jobs, frequently confused.

~ 9 min read·lesson 6 of 8
0 / 8

Tables and figures are the two structural elements newcomers misuse the hardest — tables because they used to be the layout system, figures because they look like decoration. They aren't either. A table is a grid of data with rows and columns that mean something to each other; a figure is an illustration with a caption that ties it to the prose.

When tables are the right tool

The honest test: would the data still make sense if you swapped two rows or two columns? If yes, it isn't a table — it's a list of items that happen to render in columns. Reach for <ul> plus CSS grid instead.

A real table has headers that label rows or columns, and a screen-reader user can navigate cell-to-cell and ask "what column is this in?" That's the model: rows × columns × headers, with the headers giving every cell its meaning.

Genuine table cases:

  • A pricing table comparing plans (rows: features; columns: plans).
  • A schedule (rows: time slots; columns: rooms or tracks).
  • A spreadsheet-shaped readout (rows: items; columns: properties).

Layout cases — a sidebar next to a main column, three feature blocks next to each other — are not tables. CSS Grid and Flexbox are the answer. Using <table> for layout pollutes the accessibility tree: screen readers announce "table with 3 rows and 2 columns" when the user just wanted to read your homepage.

check your understanding
You're showing three pricing plans side by side, each with a name, price, and feature list. Each plan is independent — a user reads one and decides. Which markup fits?

Table anatomy

A complete table has more parts than most beginners use:

  • <table> — the root.
  • <caption> — the table's title, sitting above (or below, with CSS) the data. Screen readers announce it as the table's name.
  • <thead>, <tbody>, <tfoot> — group the header, body, and footer rows. Browsers use them for printing (repeating thead on each page) and for sticky headers.
  • <tr> — table row.
  • <th> — header cell. Use scope="col" for column headers, scope="row" for row headers. The scope tells screen readers which cells this header labels.
  • <td> — data cell.
schedule.html
<table>
<caption>Conference schedule, day 1</caption>
<thead>
  <tr>
    <th scope="col">Time</th>
    <th scope="col">Track A</th>
    <th scope="col">Track B</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th scope="row">09:00</th>
    <td>Opening keynote</td>
    <td>Open</td>
  </tr>
  <tr>
    <th scope="row">10:00</th>
    <td>HTML for working programmers</td>
    <td>CSS layout in 2025</td>
  </tr>
</tbody>
</table>

When the table has time-row headers and topic-column headers, both axes need <th> with the right scope. A screen reader navigating to "HTML for working programmers" can then announce "10:00, Track A" — the two headers that give that cell its meaning.

Tip

colspan and rowspan let a single cell cover multiple columns or rows. Useful for hierarchical headers ("Q1 2025" spanning Jan/Feb/Mar columns underneath). Use them only when the data really does span — don't fake layout this way.

check your understanding
In a schedule table with time labels down the left and track titles across the top, which markup correctly labels both axes for a screen reader?

Figures

A <figure> wraps content that could be referenced from elsewhere in the document — an illustration, a code block, a chart, a quote — together with its <figcaption>. It's the markup equivalent of a printed book's "Figure 3.2: …"

figure.html
<figure>
<img src="parser-flow.svg"
     alt="Diagram of the HTML parser, with input bytes flowing into a tokenizer, then a tree builder, then the DOM.">
<figcaption>The HTML parser, in three stages.</figcaption>
</figure>

The caption isn't a tooltip and isn't a duplicate of the alt. Alt is what a screen reader reads when it encounters the image; the caption is part of the visible prose, anchoring the figure to the surrounding paragraphs. They serve different audiences and should usually say different things.

<figure> is a sectioning root — a <h1> inside it doesn't bleed into the document outline. Practically, that means a figure can carry its own little micro-hierarchy without disturbing the page's structure.

The figure isn't only for images. Code listings, blockquotes, charts (a <canvas> or inline SVG), even a video can sit inside one when the surrounding prose refers to "the example below" or "Figure 4."

check your understanding
You have an illustration with the alt "Bar chart of monthly revenue from Jan to Jun 2025." What's the best <figcaption>?
← prevnext lesson →
KeepLearningcertificate
for completing
HTML basics
0 of 8 read