Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Tables display tabular data with full-width layout, collapsed borders, tabular numerals, and automatic row hover states. Includes variants for striped, compact, and bordered styles plus data attributes for density, sticky headers, and row states.
The <table> element displays tabular data arranged in rows and columns. Vanilla Breeze styles tables with full-width layout (inline-size: 100%), collapsed borders, and font-variant-numeric: tabular-nums so digits align properly in columns. Header cells get a raised surface background with medium-weight bottom borders, and body rows include automatic hover states for improved scannability.
Footer rows (<tfoot>) are styled with bold text and a raised background to visually separate summary data from detail rows.
<dl> for definition/description lists<layout-grid> for responsive card layouts<data-table> web componentA well-structured table includes a <caption> for accessibility, <thead> for column headers with scope attributes, <tbody> for data rows, and optionally a <tfoot> for summary rows. Use data-numeric on cells containing numbers to right-align and enable tabular numerals.
<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> <th scope="col" data-numeric>Q3</th> <th scope="col" data-numeric>Q4</th> </tr> </thead> <tbody> <tr> <th scope="row">Widgets</th> <td data-numeric>$12,400</td> <td data-numeric>$14,200</td> <td data-numeric>$13,800</td> <td data-numeric>$16,100</td> </tr> <tr> <th scope="row">Gadgets</th> <td data-numeric>$8,300</td> <td data-numeric>$9,100</td> <td data-numeric>$10,500</td> <td data-numeric>$11,200</td> </tr> </tbody> <tfoot> <tr> <th scope="row">Total</th> <td data-numeric>$26,300</td> <td data-numeric>$29,500</td> <td data-numeric>$30,200</td> <td data-numeric>$34,700</td> </tr> </tfoot></table>
Three class-based variants modify the table appearance. They can be combined freely.
<table class="striped"> <!-- Alternating row backgrounds --></table> <table class="compact"> <!-- Reduced cell padding --></table> <table class="bordered"> <!-- Full borders on all cells --></table> <table class="striped compact bordered"> <!-- Variants can be combined --></table>
| Class | Effect |
|---|---|
.striped |
Alternating odd-row backgrounds using var(--color-surface-raised) |
.compact |
Reduced cell padding (size-xs / size-s) |
.bordered |
Full borders on every cell using var(--border-width-thin) |
data-densityControls cell padding independently of the .compact class. Useful when you want density control via attributes rather than classes.
<table data-density="compact"> <!-- Tighter padding: size-2xs / size-xs --></table> <table data-density="comfortable"> <!-- Roomier padding: size-m / size-l --></table>
| Value | Padding |
|---|---|
compact |
size-2xs / size-xs |
comfortable |
size-m / size-l |
data-stickyMakes the header row or first column sticky during scroll.
<table data-sticky="header"> <!-- thead sticks to viewport top on scroll --></table> <table data-sticky="column"> <!-- First column sticks on horizontal scroll --></table>
| Value | Effect |
|---|---|
header |
thead th becomes position: sticky at top |
column |
First td/th in each row sticks at inline-start |
data-numericApplied to individual <th> and <td> cells to right-align content and enforce font-variant-numeric: tabular-nums for proper digit alignment.
<th scope="col" data-numeric>Revenue</th><td data-numeric>$150,000</td>
data-sortApplied to <th> elements to indicate sortable columns. Adds a pointer cursor and appends a sort indicator character.
<th data-sort>Name</th><!-- Renders cursor: pointer and appends ⇅ indicator -->
Data attributes on <tr> elements control visual row states without JavaScript class toggling.
<tr data-selected> <!-- Interactive highlight background --></tr> <tr data-highlight> <!-- Warning/attention background --></tr> <tr data-disabled> <!-- Reduced opacity, no pointer events --></tr>
| Attribute | Effect |
|---|---|
data-selected |
Interactive-tinted background at 15% opacity |
data-highlight |
Warning-tinted background at 15% opacity |
data-disabled |
50% opacity with pointer-events: none |
The complete set of table styles applied by Vanilla Breeze. All values use design tokens, so tables adapt automatically to any theme.
table { inline-size: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; text-align: start;} th { padding: var(--size-s) var(--size-m); font-weight: 600; background: var(--color-surface-raised); border-block-end: var(--border-width-medium) solid var(--color-border);} td { padding: var(--size-s) var(--size-m); border-block-end: var(--border-width-thin) solid var(--color-border); vertical-align: top;} tbody tr:hover { background: var(--color-surface-raised);} tfoot td { font-weight: 600; background: var(--color-surface-raised); border-block-start: var(--border-width-medium) solid var(--color-border); border-block-end: none;} /* Variants */table.striped tbody tr:nth-child(odd) { background: var(--color-surface-raised); }table.compact :is(th, td) { padding: var(--size-xs) var(--size-s); }table.bordered :is(th, td) { border: var(--border-width-thin) solid var(--color-border); } /* Density */table[data-density="compact"] :is(th, td) { padding: var(--size-2xs) var(--size-xs); }table[data-density="comfortable"] :is(th, td) { padding: var(--size-m) var(--size-l); } /* Sticky */table[data-sticky="header"] thead th { position: sticky; inset-block-start: 0; z-index: 1; }table[data-sticky="column"] :is(td, th):first-child { position: sticky; inset-inline-start: 0; z-index: 1; } /* Numeric alignment */:is(td, th)[data-numeric] { text-align: end; font-variant-numeric: tabular-nums; } /* Row states */tr[data-selected] { background: oklch(from var(--color-interactive) l c h / 0.15); }tr[data-disabled] { opacity: 0.5; pointer-events: none; }tr[data-highlight] { background: oklch(from var(--color-warning) l c h / 0.15); }
<caption>: provides context for screen reader users navigating to the table<th> with scope: define whether headers apply to columns (scope="col") or rows (scope="row")<thead>, <tbody>, <tfoot>: helps assistive technologies understand table regionsscope="colgroup" for multi-level headers<caption> - table title for accessibility<colgroup> and <col> - column grouping and styling<thead>, <tbody>, <tfoot> - row group sections<tr> - table rows with state attributes<th> and <td> - header and data cells<dl> - use instead for key-value data<data-table> - interactive data grid with sorting, filtering, and pagination