th
The th element defines a header cell in a table. Vanilla Breeze styles headers with a raised background and semi-bold weight. Always use scope for accessibility. Supports sort indicators and numeric alignment via data attributes.
Description
The <th> (table header) element defines a cell that acts as a header for a group of table cells. Headers can apply to columns, rows, or groups of either.
Vanilla Breeze styles header cells with a raised background (var(--color-surface-raised)), semi-bold font weight (600), and a thicker bottom border (var(--border-width-medium)) to visually distinguish them from data cells.
When to Use
- Column headers: In
<thead>rows withscope="col" - Row headers: First cell of data rows with
scope="row" - Group headers: Headers spanning multiple columns/rows with
scope="colgroup"orscope="rowgroup"
When to Use td Instead
- Data cells: Cells containing actual data values
- Summary cells: Totals in
<tfoot>(though the label cell may be<th>)
The scope Attribute
The scope attribute is essential for accessibility. It tells assistive technologies which cells the header applies to. Always include it.
| Value | Description | Use Case |
|---|---|---|
col |
Header applies to all cells in the column | Column headers in <thead> |
row |
Header applies to all cells in the row | Row headers in first cell of <tbody> rows |
colgroup |
Header applies to multiple columns | Group headers used with colspan |
rowgroup |
Header applies to multiple rows | Section headers spanning all columns |
Examples
Column and Row Headers
This example shows both scope="col" for column headers and scope="row" for row headers. Screen readers use these to announce context when navigating cells.
<thead> <tr> <th scope="col">Name</th> <th scope="col">Department</th> <th scope="col">Location</th> <th scope="col">Start Date</th> </tr></thead>
<tr> <th scope="row">Monthly Price</th> <td>$9</td> <td>$29</td> <td>$99</td></tr>
Column Group Headers
Use scope="colgroup" with colspan for headers that span multiple columns, commonly seen in multi-level header rows.
<thead> <tr> <th scope="col" rowspan="2">Region</th> <th scope="colgroup" colspan="2">Q1</th> <th scope="colgroup" colspan="2">Q2</th> </tr> <tr> <th scope="col" data-numeric>Revenue</th> <th scope="col" data-numeric>Profit</th> <th scope="col" data-numeric>Revenue</th> <th scope="col" data-numeric>Profit</th> </tr></thead>
Row Group Headers
Use scope="rowgroup" for section headers that apply to multiple rows within a group.
<tbody> <tr> <th scope="rowgroup" colspan="3">Engineering</th> </tr> <tr> <td>Software</td> <td data-numeric>$25,000</td> <td data-numeric>$23,500</td> </tr> <tr> <td>Hardware</td> <td data-numeric>$50,000</td> <td data-numeric>$48,200</td> </tr></tbody>
Basic Table
A standard table showing headers in context with data rows.
Sort Indicators
Add data-sort to make a column sortable. Vanilla Breeze appends a sort indicator via ::after. The value specifies the data type for sort logic.
data-sort="string"- Alphabetical sortingdata-sort="number"- Numeric sortingdata-sort="date"- Date sorting
When active, the <data-table> component sets aria-sort="ascending" or aria-sort="descending" on the <th>, which triggers the directional arrow icon.
<thead> <tr> <th scope="col" data-sort="string">Name</th> <th scope="col" data-sort="string">Department</th> <th scope="col" data-sort="date">Start Date</th> <th scope="col" data-sort="number" data-numeric>Salary</th> </tr></thead>
Numeric and Alignment Attributes
data-numeric
Use data-numeric on header cells for numeric columns. This right-aligns the header text and applies font-variant-numeric: tabular-nums for proper digit alignment.
<th scope="col" data-numeric>Quantity</th><th scope="col" data-numeric>Unit Price</th><th scope="col" data-numeric>Total</th>
data-align
Use data-align for explicit text alignment when the default (start) or data-numeric (end) are not appropriate.
<th scope="col" data-align="start">Name</th><th scope="col" data-align="center">Status</th><th scope="col" data-align="end">Amount</th>
VB Data Attributes
| Attribute | Values | Description |
|---|---|---|
data-numeric |
Boolean attribute | Right-aligns content and uses tabular numerals |
data-align |
start, center, end |
Explicit text alignment override |
data-sort |
string, number, date |
Enables sort indicator; value sets sort data type |
Standard HTML Attributes
| Attribute | Values | Description |
|---|---|---|
scope |
col, row, colgroup, rowgroup |
Specifies which cells the header applies to (required for a11y) |
colspan |
Positive integer | Number of columns the header spans |
rowspan |
Positive integer | Number of rows the header spans |
abbr |
String | Abbreviated version of header content for screen readers |
CSS Reference
th { padding: var(--size-s) var(--size-m); font-weight: 600; text-align: start; background: var(--color-surface-raised); border-block-end: var(--border-width-medium) solid var(--color-border);} /* Numeric alignment */th[data-numeric] { text-align: end; font-variant-numeric: tabular-nums;} /* Explicit alignment */th[data-align="start"] { text-align: start; }th[data-align="center"] { text-align: center; }th[data-align="end"] { text-align: end; } /* Sort indicator (unsorted) */th[data-sort]::after { content: " \21C5"; /* ⇅ */ opacity: 0.4;} /* Sort ascending */th[data-sort="asc"]::after,th[aria-sort="ascending"]::after { content: " \2191"; /* ↑ */ opacity: 1;} /* Sort descending */th[data-sort="desc"]::after,th[aria-sort="descending"]::after { content: " \2193"; /* ↓ */ opacity: 1;}
Accessibility
- Always use scope: The
scopeattribute is essential for screen readers to associate headers with data cells - Screen reader announcement: When navigating to a data cell, the associated headers are announced
- Complex tables: For tables with multiple header levels, consider using the
headersattribute on<td>elements - Implicit roles:
<th>has an implicit ARIA role ofcolumnheader(withscope="col") orrowheader(withscope="row") - Sort state: When a column is sorted, use
aria-sort="ascending"oraria-sort="descending"on the<th>