caption
Provides a title or description for a table. Vanilla Breeze styles captions with start-aligned text, muted color, and medium font weight to clearly label tabular data without competing with the data itself.
Description
The <caption> element must be the first child of a <table>. It provides a programmatic association between the table and its description, which screen readers announce when a user navigates to the table.
Vanilla Breeze styles captions with text-align: start (RTL-aware), font-weight: 500 for medium emphasis, and var(--color-text-muted) so the label does not compete visually with the data. Padding matches the cell padding (var(--size-s) var(--size-m)) to keep alignment consistent with table content.
When to Use
- Every data table: all tables containing meaningful data should have a caption
- Table identification: when multiple tables appear on the same page
- Context setting: to explain what data the table contains
- Time-sensitive data: to indicate the date or period the data represents
When Not Required
- Tables with adjacent headings: if a heading immediately precedes the table, use
aria-labelledbyto link them instead - Non-tabular content: for image descriptions, use
<figcaption>inside a<figure>
Basic Example
The demo below shows a complete table with a caption as its first child, followed by <thead>, <tbody>, and <tfoot>. Note how the caption aligns with the table content.
<table> <caption>Quarterly Sales Report</caption> <thead> <tr> <th scope="col">Product</th> <th scope="col" data-numeric>Q1</th> <th scope="col" data-numeric>Q2</th> </tr> </thead> <tbody> <!-- Table data --> </tbody></table>
Rich Captions
Captions can contain inline elements like <small> for secondary information such as data sources or date ranges.
<table> <caption> Quarterly Sales Report <br /> <small>Data from January - March 2024</small> </caption> <!-- thead, tbody... --></table>
Alternative: aria-labelledby
When a visible heading immediately precedes the table and serves as its label, you can use aria-labelledby instead of duplicating the text in a caption.
<h3 id="sales-heading">Monthly Sales Data</h3><table aria-labelledby="sales-heading"> <!-- Table content without caption --></table>
CSS Reference
The styles Vanilla Breeze applies to caption elements.
caption { padding: var(--size-s) var(--size-m); text-align: start; font-weight: 500; color: var(--color-text-muted);}
| Property | Value | Purpose |
|---|---|---|
padding |
var(--size-s) var(--size-m) |
Matches cell padding for visual alignment |
text-align |
start |
Left-aligned in LTR, right-aligned in RTL |
font-weight |
500 |
Medium weight for subtle emphasis |
color |
var(--color-text-muted) |
Muted to differentiate from data content |
Accessibility
- Screen reader announcement: when a user navigates to a table, the caption is announced first, providing immediate context
- Be descriptive: write captions that explain what data the table contains, not just "Table 1"
- Include temporal context: if data is time-sensitive, include the relevant period
- WCAG requirement: Success Criterion 1.3.1 requires data tables to be programmatically identifiable
Related
<table>- parent container (caption must be its first child)<thead>- header group that follows the caption<figcaption>- similar purpose for figures and images (compare:<caption>is for tables,<figcaption>is for figures)<summary>- similar "label" role for<details>disclosure widgets