Figures and Captions
How to associate an image, diagram, or code block with its caption using figure and figcaption.
When you place an image above a paragraph that describes it, there is no connection between them in the HTML. The image is one element. The paragraph is another. The browser, a screen reader, and a search engine all treat them as unrelated.
<figure> and <figcaption> create an explicit relationship between a piece of content and its caption.
The problem with adjacent text
Here is what the broken version looks like:
<!-- No relationship between the image and the caption paragraph -->
<img src="sales-chart.png" alt="Sales chart">
<p>Figure 1: Q1 2024 sales by month. March reached 1,240 units, the highest of the quarter.</p>From the browser's point of view, this is an image followed by an unrelated paragraph. Three things go wrong:
- A screen reader reads the alt text, then reads the paragraph as a separate piece of prose. There is no signal that the paragraph is describing the image.
- If CSS reflows the layout (say, the image floats right), the paragraph might end up visually adjacent to a different image.
- Search engines cannot infer that the paragraph is a caption.
<figure> and <figcaption>
<figure> is a container for self-contained content. <figcaption> is the caption for that content. Together, they create a machine-readable association.
<figure>
<img src="sales-chart.png" alt="Bar chart showing Q1 2024 sales by month" width="800" height="500">
<figcaption>Figure 1: Q1 2024 sales by month. March reached 1,240 units, the highest of the quarter.</figcaption>
</figure>Screen readers now understand that the caption belongs to the image. The <figcaption> can go before or after the content inside <figure>. Put it after for descriptive captions (the most common case). Put it before when the caption introduces the content -- for example, a title above a diagram.
<!-- Caption after: describes what the figure shows -->
<figure>
<img src="network-diagram.png" alt="Diagram showing three servers connected to a central load balancer" width="700" height="420">
<figcaption>The production infrastructure routes all traffic through a central load balancer before reaching the application servers.</figcaption>
</figure>
<!-- Caption before: introduces the figure -->
<figure>
<figcaption>Figure 3: Memory usage over a 24-hour period.</figcaption>
<img src="memory-graph.png" alt="Line graph showing memory usage peaking at 87% between 2pm and 4pm" width="700" height="350">
</figure>The <figcaption> must be a direct child of <figure>
Nesting <figcaption> inside another element inside <figure> breaks the association.
<!-- Wrong: figcaption nested inside a div, association is lost -->
<figure>
<img src="chart.png" alt="...">
<div>
<figcaption>This caption is no longer correctly associated.</figcaption>
</div>
</figure>
<!-- Correct: figcaption is a direct child of figure -->
<figure>
<img src="chart.png" alt="...">
<figcaption>This caption is correctly associated.</figcaption>
</figure>When to use <figure>
<figure> is for content that is referenced from the main text but could be moved or removed without breaking the flow of the surrounding prose. The classic test: if you can move the content to an appendix and the surrounding text still makes sense, it belongs in a <figure>.
Use <figure> for:
- An image with a caption
- A code sample with an explanation
- A table with a title or description
- A chart, diagram, or illustration referred to from the prose ("see Figure 2 below")
Do not use <figure> for:
- A product thumbnail in a shop grid (no caption, no reference from prose)
- A decorative background or section divider (use CSS, not
<img>at all) - Every image just to have a container (only wrap in
<figure>if there is a meaningful caption or the content is self-contained)
<figure> for code blocks
<figure> works for code samples too. This is useful in documentation or tutorials when you want to label what a code block is demonstrating.
<figure>
<pre><code>const order = {
id: 'ord-8821',
total: 49.95,
status: 'dispatched'
};</code></pre>
<figcaption>An order object returned by the API after a successful purchase.</figcaption>
</figure><figure> for tables
A table with a caption uses <figure> in the same way:
<figure>
<figcaption>Table 1: Average monthly rainfall in London (mm)</figcaption>
<table>
<thead>
<tr><th>Jan</th><th>Feb</th><th>Mar</th><th>Apr</th></tr>
</thead>
<tbody>
<tr><td>55</td><td>40</td><td>41</td><td>43</td></tr>
</tbody>
</table>
</figure>Tables have their own <caption> element that goes inside <table>. Both approaches are valid. Using <figure> with <figcaption> is common when you want to style the caption the same way as other figure captions on the page.
Alt text and captions together
The alt attribute and <figcaption> serve different audiences in different ways.
altis read by screen readers when they encounter the<img>element. It is not displayed visually.<figcaption>is visible to all users: sighted users see it, screen readers read it as part of the document.
When the <figcaption> fully describes the image, the alt can be shorter or empty. Duplicating the exact same text in both means screen reader users hear it twice.
<!-- Wrong: identical text in alt and figcaption, screen readers repeat it -->
<figure>
<img
src="london-map.png"
alt="A street map of central London showing the walking route from Paddington Station to Hyde Park, marked in blue."
width="900"
height="620"
>
<figcaption>A street map of central London showing the walking route from Paddington Station to Hyde Park, marked in blue.</figcaption>
</figure>
<!-- Correct: alt is empty because the figcaption describes the image for everyone -->
<figure>
<img
src="london-map.png"
alt=""
width="900"
height="620"
>
<figcaption>Walking route from Paddington Station to Hyde Park, central London. The blue line shows the recommended path, approximately 1.2 km, taking 12 minutes on foot.</figcaption>
</figure>The tradeoff: if the image fails to load, only the alt text displays inline. An empty alt means nothing replaces the broken image. A short, meaningful alt handles the broken-image case while the figcaption handles the descriptive case.
A reasonable approach is a short alt for the broken-image fallback, and a fuller description in the figcaption:
<figure>
<img
src="london-map.png"
alt="Map of central London"
width="900"
height="620"
>
<figcaption>Walking route from Paddington Station to Hyde Park. The blue line marks the recommended 1.2 km path, approximately 12 minutes on foot.</figcaption>
</figure>Common mistakes
<figcaption> outside <figure>. The association only works when <figcaption> is inside <figure>. Placed outside, it is just a paragraph.
Using <figure> for every image. If an image has no caption and is not referenced from the text, it does not need <figure>. A <figure> with no <figcaption> is valid HTML, but it signals to browsers and assistive technology that the content is self-contained. Reserve that signal for when it is true.
Writing identical text in alt and <figcaption>. Screen reader users hear the content twice. Write a complementary short description in alt and put the full detail in <figcaption>.
Using a <p> adjacent to an image instead of <figcaption>. A paragraph after an image looks like a caption but carries no semantic association. Use <figure> and <figcaption> when you want a genuine caption.
Putting <figcaption> inside a nested element. <figcaption> must be a direct child of <figure>, not nested inside a <div> or <p> inside the figure.
Exercise
Build a page that uses <figure> correctly in three different situations.
- Create a figure with a product image (use
https://placehold.co/600x400) and a caption describing a fictional product. Use a shortaltfor the broken-image fallback and a fuller description in<figcaption>. - Create a figure wrapping a
<pre><code>block. The code can be a simple HTML snippet. Write a<figcaption>that explains what the code demonstrates. - Add a standalone image with no
<figure>-- a small decorative rule image (https://placehold.co/600x4). Use an emptyaltattribute. This shows the contrast between when<figure>is and is not appropriate.