HTMLCaption & Column Groups (<caption>, <colgroup>)

Caption & Column Groups (<caption>, <colgroup>)

Two lesser-known table elements round out a fully structured table: <caption> gives the whole table an accessible title, and <colgroup>/<col> let you style entire columns without repeating CSS on every single cell.

<caption> — An Accessible Table Title

<caption> must be the first child of <table>, immediately after the opening tag. It provides the table's accessible name — a screen reader announces it before reading any cell content, similar to how a heading introduces a section.

HTML
<table>
  <caption>Quarterly Revenue by Product Line (USD, millions)</caption>
  <thead>
    <tr>
      <th scope="col">Product</th>
      <th scope="col">Q1</th>
      <th scope="col">Q2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Hardware</th>
      <td>12.4</td>
      <td>13.1</td>
    </tr>
  </tbody>
</table>
Note
A heading placed above the table (like an <h3>) is visually similar but not programmatically connected to the table. <caption> is the semantically correct choice — it is read as part of the table itself, and works correctly even if the table is later moved or embedded elsewhere on the page.
Warning
A table can only have one <caption>, and it must come immediately after the opening <table> tag — before any <thead>, <colgroup>, or <tr>.
Styling the Caption

CSS
caption {
  caption-side: top; /* or "bottom" to place it below the table */
  font-weight: 600;
  text-align: left;
  padding: 8px 0;
}
<colgroup> and <col> — Column-Wide Styling

Normally, styling "every cell in this column" means writing a CSS selector like{' '} td:nth-child(2) or repeating a class on every cell in that column. <colgroup> and{' '} <col> let you describe column-level presentation once, directly in the table's markup.

HTML
<table>
  <caption>Server Inventory</caption>
  <colgroup>
    <col style="background-color: #f5f5f5;">
    <col span="2">
    <col style="background-color: #fffbe6;">
  </colgroup>
  <thead>
    <tr>
      <th scope="col">Hostname</th>
      <th scope="col">CPU</th>
      <th scope="col">RAM</th>
      <th scope="col">Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>web-01</td>
      <td>8 cores</td>
      <td>32 GB</td>
      <td>Online</td>
    </tr>
    <tr>
      <td>web-02</td>
      <td>8 cores</td>
      <td>64 GB</td>
      <td>Maintenance</td>
    </tr>
  </tbody>
</table>

Attribute

Where

Purpose

<colgroup>

Wraps one or more <col> elements

Groups columns for shared styling

span

On <col> or <colgroup>

How many columns this entry applies to (default 1)

style / class

On <col>

Only a small set of CSS properties actually apply (background, border, width, visibility)

Note
<colgroup> must appear right after <caption> (or right after the opening <table> tag if there's no caption) — before any <thead> or row content.
The span Attribute

Rather than writing three separate <col> elements for three visually identical columns, use span on a single <col> to cover a range.

HTML
<colgroup>
  <col> <!-- column 1: default -->
  <col span="3" style="background-color: #eef7ff;"> <!-- columns 2, 3, 4 share this style -->
</colgroup>
Warning
Only a limited set of CSS properties actually take effect on <col> — mainly background, border, width, and visibility. Text properties like color or font-weight do not apply through <col> because column elements don't actually wrap any content — cell styles still win. Use column-based CSS selectors for anything beyond that limited set.
A Common Practical Use: Fixed Column Widths

HTML
<table>
  <colgroup>
    <col style="width: 40%;">
    <col style="width: 20%;">
    <col style="width: 20%;">
    <col style="width: 20%;">
  </colgroup>
  <thead>
    <tr>
      <th scope="col">Description</th>
      <th scope="col">Qty</th>
      <th scope="col">Unit Price</th>
      <th scope="col">Total</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Wireless Mouse</td>
      <td>2</td>
      <td>$24.99</td>
      <td>$49.98</td>
    </tr>
  </tbody>
</table>
Tip
Setting column widths via <colgroup> is especially handy on invoices and reports, where you want consistent column proportions without repeating a width style on every single <td> in that column.
Key Takeaways
  1. <caption> gives a table an accessible title and must be the first child of <table>.

  2. A table can have only one <caption>, distinct from a nearby heading element.

  3. <colgroup>/<col> apply styling to entire columns without repeating it on every cell.

  4. Only a limited set of CSS properties (background, border, width, visibility) actually apply through <col>.

  5. span lets one <col> cover multiple columns at once.