<!-- Generated by tools/docs.php from docs/src/table.html - edit the source, not this file. -->

# Tables

A list of records: a title that links to the record, a line under it, a note when something is wrong, a column of checks for batch actions and the row's own actions at the end.

## Examples

`table` on the `<table>`; the row under the pointer lights on a device with one, in the color of `--redz-row-hover`, set on the page or on one table, and `table-static` keeps a table's rows still. The head stays at the top of the screen as the page scrolls. Columns that only help on a wide screen hide below `md` of their card.

```html
<section class="card" aria-labelledby="table-list-title">
	<div class="card-header"><h2 id="table-list-title">Excursions</h2><span class="text-muted fs-12">3 of 28</span></div>
	<div class="card-body p-0">
		<table class="table">
			<thead>
				<tr>
					<th class="table-check"><input class="check" type="checkbox" aria-label="Select all"></th>
					<th>Excursion</th>
					<th class="text-end d-none md:d-table-cell">Price from</th>
					<th class="d-none md:d-table-cell">Status</th>
					<th class="table-actions"><span class="visually-hidden">Actions</span></th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td><input class="check" type="checkbox" aria-label="Select: North Bay"></td>
					<td><a class="table-title" href="#table-list">North Bay: marine park by speedboat</a><div class="table-sub d-none md:d-block">/excursions/north-bay/</div></td>
					<td class="text-end tabular-nums text-nowrap d-none md:d-table-cell">2,500 THB</td>
					<td class="d-none md:d-table-cell"><span class="badge"><i class="bi bi-check2" aria-hidden="true"></i>Published</span></td>
					<td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Edit: North Bay"><i class="bi bi-pencil" aria-hidden="true"></i></button></td>
				</tr>
				<tr class="table-danger">
					<td><input class="check" type="checkbox" aria-label="Select: Elephant sanctuary"></td>
					<td><a class="table-title" href="#table-list">Elephant sanctuary: feeding and a walk</a><div class="table-note"><i class="bi bi-x-octagon-fill" aria-hidden="true"></i><span class="text-muted">Did not rebuild: a PHP warning in the theme template</span></div></td>
					<td class="text-end tabular-nums text-nowrap d-none md:d-table-cell">2,600 THB</td>
					<td class="d-none md:d-table-cell"><span class="badge badge-subtle-danger"><i class="bi bi-x-octagon" aria-hidden="true"></i>Failed</span></td>
					<td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Rebuild: Elephant sanctuary"><i class="bi bi-arrow-repeat" aria-hidden="true"></i></button></td>
				</tr>
				<tr class="table-warning">
					<td><input class="check" type="checkbox" aria-label="Select: Night market"></td>
					<td><a class="table-title" href="#table-list">Night market and street food</a><div class="table-note"><i class="bi bi-exclamation-triangle-fill" aria-hidden="true"></i><span class="text-muted">The Thai translation is older than the English</span></div></td>
					<td class="text-end tabular-nums text-nowrap d-none md:d-table-cell">900 THB</td>
					<td class="d-none md:d-table-cell"><span class="badge badge-subtle-warning"><i class="bi bi-clock-history" aria-hidden="true"></i>Stale</span></td>
					<td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Edit: Night market"><i class="bi bi-pencil" aria-hidden="true"></i></button></td>
				</tr>
				<tr class="table-secondary">
					<td><input class="check" type="checkbox" aria-label="Select: Folk dance"></td>
					<td><a class="table-title" href="#table-list">Folk dance: an evening at the stadium</a><div class="table-sub d-none md:d-block">withdrawn from the sites</div></td>
					<td class="text-end tabular-nums text-nowrap d-none md:d-table-cell">1,500 THB</td>
					<td class="d-none md:d-table-cell"><span class="badge"><i class="bi bi-eye-slash" aria-hidden="true"></i>Withdrawn</span></td>
					<td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Edit: Folk dance"><i class="bi bi-pencil" aria-hidden="true"></i></button></td>
				</tr>
			</tbody>
		</table>
	</div>
</section>
```

### Stripes, borders and groups

`table-striped` shades every other row, `table-striped-columns` every other column - under the hover's light and a row's tone alike; `table-group-divider` on a `tbody` draws a stronger line above it. `table-bordered` draws the lines between columns and, outside a card, the table's own frame; `table-borderless` takes the lines between rows away.

```html
<section class="card" aria-labelledby="table-variants-title">
	<div class="card-header"><h2 class="fs-14" id="table-variants-title">Boats this week</h2></div>
	<table class="table table-striped">
		<thead><tr><th scope="col">Boat</th><th class="text-end" scope="col">Trips</th><th class="text-end" scope="col">Seats sold</th></tr></thead>
		<tbody>
			<tr><td>Boat A</td><td class="text-end tabular-nums">12</td><td class="text-end tabular-nums">286</td></tr>
			<tr><td>Boat C</td><td class="text-end tabular-nums">9</td><td class="text-end tabular-nums">201</td></tr>
			<tr><td>Boat B</td><td class="text-end tabular-nums">7</td><td class="text-end tabular-nums">164</td></tr>
		</tbody>
		<tbody class="table-group-divider">
			<tr><td>All boats</td><td class="text-end tabular-nums">28</td><td class="text-end tabular-nums">651</td></tr>
		</tbody>
	</table>
</section>
<table class="table table-bordered" aria-label="Seasons on Main Island">
	<thead><tr><th scope="col">Season</th><th scope="col">Months</th><th scope="col">The sea</th></tr></thead>
	<tbody>
		<tr><td>Dry</td><td>January to April</td><td>Calm</td></tr>
		<tr><td>Hot</td><td>May to August</td><td>Calm</td></tr>
		<tr><td>Rainy</td><td>September to December</td><td>Waves</td></tr>
	</tbody>
</table>
```

### Row sizes

`data-density="compact"` tightens the rows and the controls of the element it is on and of everything inside it: a table, the card that holds it, a region, or the whole page on `<html>`. A compact table can stand beside a normal one on the same screen. Bootstrap 5 calls it `table-sm`. `data-density="comfortable"` and `data-density="spacious"` open the rows up the other way, for a short table that is the point of a page.

```html
<table class="table table-bordered" data-density="compact" aria-label="Seasons on Main Island, compact">
	<thead><tr><th scope="col">Season</th><th scope="col">Months</th><th scope="col">The sea</th></tr></thead>
	<tbody>
		<tr><td>Dry</td><td>January to April</td><td>Calm</td></tr>
		<tr><td>Hot</td><td>May to August</td><td>Calm</td></tr>
		<tr><td>Rainy</td><td>September to December</td><td>Waves</td></tr>
	</tbody>
</table>
<table class="table table-bordered" data-density="spacious" aria-label="Seasons on Main Island, spacious">
	<thead><tr><th scope="col">Season</th><th scope="col">Months</th><th scope="col">The sea</th></tr></thead>
	<tbody>
		<tr><td>Dry</td><td>January to April</td><td>Calm</td></tr>
		<tr><td>Hot</td><td>May to August</td><td>Calm</td></tr>
	</tbody>
</table>
```

### Rows that stay still

Every table lights the row under the pointer. `table-static` keeps the rows of one still, for a table with nothing to do in a row.

```html
<table class="table" aria-label="Departures">
	<tbody>
		<tr><td>North Bay</td><td>08:00</td></tr>
		<tr><td>Turtle Cove</td><td>10:30</td></tr>
	</tbody>
</table>
<table class="table table-static" aria-label="Fares">
	<tbody>
		<tr><td>Adult</td><td>1,200</td></tr>
		<tr><td>Child</td><td>600</td></tr>
	</tbody>
</table>
```

### A menu in a row

A row's menu stands in `table-actions` right after its button. While it is open the row keeps its light and its actions, wherever the pointer goes, and the menu takes nothing from the cell. Rows may also share one menu kept outside the table: each button names it, and the row of the button that opened it stays lit.

```html
<table class="table" aria-label="Departures">
	<thead>
		<tr><th scope="col">Excursion</th><th scope="col">Leaves</th><th class="table-actions"><span class="visually-hidden">Actions</span></th></tr>
	</thead>
	<tbody>
		<tr>
			<td>North Bay</td>
			<td>08:00</td>
			<td class="table-actions">
				<button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Edit: North Bay"><i class="bi bi-pencil" aria-hidden="true"></i></button>
				<button class="btn btn-sm btn-icon btn-text" type="button" commandfor="table-row-menu-bay" command="toggle-popover" aria-haspopup="menu" aria-label="More: North Bay"><i class="bi bi-three-dots" aria-hidden="true"></i></button>
				<div id="table-row-menu-bay" class="menu" popover role="menu" aria-label="More: North Bay">
					<button class="menu-item" type="button" role="menuitem"><i class="bi bi-files" aria-hidden="true"></i>Duplicate</button>
					<button class="menu-item" type="button" role="menuitem"><i class="bi bi-eye-slash" aria-hidden="true"></i>Withdraw</button>
				</div>
			</td>
		</tr>
		<tr>
			<td>Turtle Cove</td>
			<td>10:30</td>
			<td class="table-actions">
				<button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Edit: Turtle Cove"><i class="bi bi-pencil" aria-hidden="true"></i></button>
				<button class="btn btn-sm btn-icon btn-text" type="button" commandfor="table-row-menu-cove" command="toggle-popover" aria-haspopup="menu" aria-label="More: Turtle Cove"><i class="bi bi-three-dots" aria-hidden="true"></i></button>
				<div id="table-row-menu-cove" class="menu" popover role="menu" aria-label="More: Turtle Cove">
					<button class="menu-item" type="button" role="menuitem"><i class="bi bi-files" aria-hidden="true"></i>Duplicate</button>
					<button class="menu-item" type="button" role="menuitem"><i class="bi bi-eye-slash" aria-hidden="true"></i>Withdraw</button>
				</div>
			</td>
		</tr>
	</tbody>
</table>
```

### Rows that light together

Elements that share a `data-highlight` key light together: hovering or focusing one marks every element with its key `data-highlighted`, tinted - a row here and its lane on a [board](chart.md#chart-lanes), or its marker on a map. A mark the page sets itself, `data-highlighted="hold"`, stays until the page takes it away: a row flashed after a jump to it, say.

```html
<div class="hstack flex-wrap gap-8">
	<button class="btn btn-sm" type="button" data-highlight="pier">The pier</button>
	<button class="btn btn-sm" type="button" data-highlight="lake">The emerald lake</button>
</div>
<table class="table" aria-label="Stops">
	<tbody>
		<tr data-highlight="pier"><td>The pier</td><td class="tabular-nums">08:30</td></tr>
		<tr data-highlight="lake"><td>The emerald lake</td><td class="tabular-nums">11:00</td></tr>
	</tbody>
</table>
```

### Sortable columns

A header that sorts holds a `button class="table-sort"`, and the header's `aria-sort` - `ascending`, `descending` or none - draws the arrow. The page sorts - on the server or in place - and moves `aria-sort` to the column it sorted by.

```html
<table class="table" aria-label="Owners">
	<thead><tr><th scope="col" aria-sort="ascending"><button class="table-sort" type="button">Name</button></th><th scope="col"><button class="table-sort" type="button">Sites</button></th><th scope="col" class="text-end"><button class="table-sort" type="button">Paid</button></th></tr></thead>
	<tbody>
		<tr><td>Example Resort</td><td class="tabular-nums">3</td><td class="text-end tabular-nums">48,000</td></tr>
		<tr><td>Example Cruises</td><td class="tabular-nums">1</td><td class="text-end tabular-nums">9,600</td></tr>
		<tr><td>Example Divers</td><td class="tabular-nums">2</td><td class="text-end tabular-nums">21,300</td></tr>
	</tbody>
</table>
```

Where the server sorts, the header holds a link instead - `a class="table-sort"` to the same list in the other order - drawn the same way.

```html
<table class="table" aria-label="Owners, sorted by the server">
	<thead><tr><th scope="col"><a class="table-sort" href="#table-sort-links">Name</a></th><th scope="col" class="text-end" aria-sort="descending"><a class="table-sort" href="#table-sort-links">Paid</a></th></tr></thead>
	<tbody>
		<tr><td>Example Resort</td><td class="text-end tabular-nums">48,000</td></tr>
		<tr><td>Example Divers</td><td class="text-end tabular-nums">21,300</td></tr>
	</tbody>
</table>
```

### Groups and subtotals

A row `table-group` heads the rows under it: one `th scope="rowgroup"` across the table, a band that does not stick, with an end slot `table-group-end` for its count or sum. A row `table-subtotal` closes a group in bold under a line.

```html
<table class="table" aria-label="Bookings by boat">
	<thead><tr><th scope="col">Guest</th><th scope="col" class="text-end">Seats</th><th scope="col" class="text-end">Paid</th></tr></thead>
	<tbody>
		<tr class="table-group"><th scope="rowgroup" colspan="3">Boat A<span class="table-group-end">2 bookings</span></th></tr>
		<tr><td>Alex Sample</td><td class="text-end tabular-nums">2</td><td class="text-end tabular-nums">5,000</td></tr>
		<tr><td>Ben Sample</td><td class="text-end tabular-nums">3</td><td class="text-end tabular-nums">7,500</td></tr>
		<tr class="table-subtotal"><th scope="row">Boat A</th><td class="text-end tabular-nums">5</td><td class="text-end tabular-nums">12,500</td></tr>
		<tr class="table-group"><th scope="rowgroup" colspan="3">Boat C<span class="table-group-end">1 booking</span></th></tr>
		<tr><td>Chris Sample</td><td class="text-end tabular-nums">4</td><td class="text-end tabular-nums">10,000</td></tr>
		<tr class="table-subtotal"><th scope="row">Boat C</th><td class="text-end tabular-nums">4</td><td class="text-end tabular-nums">10,000</td></tr>
	</tbody>
</table>
```

The head of a table sticks under the app's header as the page scrolls; inside a region that scrolls on its own - a `dialog-body`, a `card-scroll` card's body - it sticks to the region's top.

### Wider than its card

A table with more columns than its card has room for goes in a `table-scroll`: it scrolls sideways inside the card, and `table-scroll-first` holds its first column in place, `table-scroll-last` its last, where a row's buttons stay in view. Where the browser lets an element scroll on one axis alone - Chrome 156 on - the head still sticks to the page as it scrolls down; elsewhere the head scrolls away with the page and the rest works the same. The wrapper is a named region. The library makes it a tab stop while its table is wider than it, so a keyboard can scroll it, and takes the stop away while the table fits.

```html
<section class="card" aria-labelledby="table-wide-title">
	<div class="card-header"><h2 class="fs-14" id="table-wide-title">Seats by day</h2></div>
	<div class="table-scroll table-scroll-first" role="region" aria-labelledby="table-wide-title">
		<table class="table">
			<thead><tr><th scope="col">Boat</th><th scope="col" class="text-end">Mon</th><th scope="col" class="text-end">Tue</th><th scope="col" class="text-end">Wed</th><th scope="col" class="text-end">Thu</th><th scope="col" class="text-end">Fri</th><th scope="col" class="text-end">Sat</th><th scope="col" class="text-end">Sun</th><th scope="col" class="text-end">Week</th><th scope="col" class="text-end">Last week</th><th scope="col" class="text-end">Change</th></tr></thead>
			<tbody>
				<tr><th scope="row">Boat A</th><td class="text-end tabular-nums">42</td><td class="text-end tabular-nums">38</td><td class="text-end tabular-nums">40</td><td class="text-end tabular-nums">44</td><td class="text-end tabular-nums">46</td><td class="text-end tabular-nums">48</td><td class="text-end tabular-nums">28</td><td class="text-end tabular-nums">286</td><td class="text-end tabular-nums">270</td><td class="text-end tabular-nums"><bdi>+16</bdi></td></tr>
				<tr><th scope="row">Boat C</th><td class="text-end tabular-nums">30</td><td class="text-end tabular-nums">28</td><td class="text-end tabular-nums">27</td><td class="text-end tabular-nums">31</td><td class="text-end tabular-nums">33</td><td class="text-end tabular-nums">35</td><td class="text-end tabular-nums">17</td><td class="text-end tabular-nums">201</td><td class="text-end tabular-nums">214</td><td class="text-end tabular-nums"><bdi>-13</bdi></td></tr>
				<tr><th scope="row">Boat B</th><td class="text-end tabular-nums">22</td><td class="text-end tabular-nums">20</td><td class="text-end tabular-nums">24</td><td class="text-end tabular-nums">23</td><td class="text-end tabular-nums">25</td><td class="text-end tabular-nums">30</td><td class="text-end tabular-nums">20</td><td class="text-end tabular-nums">164</td><td class="text-end tabular-nums">150</td><td class="text-end tabular-nums"><bdi>+14</bdi></td></tr>
			</tbody>
		</table>
	</div>
</section>
```

```html
<section class="card" aria-labelledby="table-wide-last-title">
	<div class="card-header"><h2 class="fs-14" id="table-wide-last-title">Rates</h2></div>
	<div class="table-scroll table-scroll-last" role="region" aria-labelledby="table-wide-last-title">
		<table class="table">
			<thead><tr><th scope="col">Boat</th><th scope="col" class="text-end">Low</th><th scope="col" class="text-end">High</th><th scope="col" class="text-end">Peak</th><th scope="col" class="text-end">Children</th><th scope="col" class="text-end">Groups</th><th scope="col" class="text-end">Agents</th><th scope="col" class="text-end">Guides</th><th scope="col" class="text-end">Fuel</th><th scope="col" class="text-end">Park fee</th><th scope="col" class="text-end">Insurance</th><th scope="col" class="text-end">Status</th></tr></thead>
			<tbody>
				<tr><th scope="row">Boat A</th><td class="text-end tabular-nums">2,500</td><td class="text-end tabular-nums">2,900</td><td class="text-end tabular-nums">3,400</td><td class="text-end tabular-nums">1,900</td><td class="text-end tabular-nums">2,200</td><td class="text-end tabular-nums">2,100</td><td class="text-end tabular-nums">900</td><td class="text-end tabular-nums">300</td><td class="text-end tabular-nums">300</td><td class="text-end tabular-nums">120</td><td class="text-end"><button class="btn btn-xs btn-primary" type="button">Save</button></td></tr>
				<tr><th scope="row">Boat C</th><td class="text-end tabular-nums">2,200</td><td class="text-end tabular-nums">2,600</td><td class="text-end tabular-nums">3,000</td><td class="text-end tabular-nums">1,700</td><td class="text-end tabular-nums">2,000</td><td class="text-end tabular-nums">1,900</td><td class="text-end tabular-nums">800</td><td class="text-end tabular-nums">280</td><td class="text-end tabular-nums">300</td><td class="text-end tabular-nums">110</td><td class="text-end"><button class="btn btn-xs btn-primary" type="button">Save</button></td></tr>
			</tbody>
		</table>
	</div>
</section>
```

A product sets the look of every table head in its tokens: `--redz-table-head-bg`, `--redz-table-head-text`, `--redz-table-head-weight`, and `--redz-table-head-border`, the whole line under it.

### The current, the chosen and the running row

A row with `aria-current` - the record open beside the list - carries the accent's mark at its start; a row with `aria-selected="true"`, chosen in a grid of rows, is tinted; `table-active`, Bootstrap's name, marks the row that is running now.

```html
<table class="table" aria-label="Jobs">
	<tbody>
		<tr aria-current="true"><td>Rebuild the Thai pages</td><td class="text-muted">Open on the right</td></tr>
		<tr aria-selected="true"><td>Import the price list</td><td class="text-muted">Chosen</td></tr>
		<tr class="table-active"><td>Send the morning letters</td><td class="text-muted">Running now</td></tr>
		<tr><td>Clean the old photos</td><td class="text-muted">Waiting</td></tr>
	</tbody>
</table>
```

### A whole row as a link

The row's title link with Bootstrap's `stretched-link` makes the whole row a link: a click anywhere on it but on its own controls and their cells (`table-check`, `table-actions`) follows the title - with `Ctrl`, `Cmd` or the middle button into a new tab - unless the person was selecting its text. The title stays the one link a keyboard and a screen reader meet. The library does it by script, as Safari gives a positioned row no box for the link's cover.

```html
<table class="table" aria-label="Guides">
	<tbody>
		<tr><td><a class="table-title stretched-link" href="#table-links">Alex Sample</a><div class="table-sub">Thai, English</div></td><td class="tabular-nums">12 tours</td><td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Message: Alex Sample"><i class="bi bi-chat" aria-hidden="true"></i></button></td></tr>
		<tr><td><a class="table-title stretched-link" href="#table-links">Hana Sample</a><div class="table-sub">Japanese, English</div></td><td class="tabular-nums">7 tours</td><td class="table-actions"><button class="btn btn-sm btn-icon btn-text" type="button" aria-label="Message: Hana Sample"><i class="bi bi-chat" aria-hidden="true"></i></button></td></tr>
	</tbody>
</table>
```

## States

A row's tone marks what needs attention: `table-danger` failed, `table-warning` needs a look, `table-secondary` is out of use. On a pointer screen the row's actions show on hover and on focus; on a touch screen they always show.

## Keyboard and accessibility

- The row's title is a link; its actions are buttons named with the record - "Edit: North Bay", not a column of identical "Edit".
- The column of actions has a hidden header, and each check its own name: "Select: North Bay".
- A tone is never the only sign: a failed row also says why in its `table-note`, with an icon.
- Numbers sit at the end of their cells with `tabular-nums`, so their digits line up.
- A table being reloaded turns busy on its card's body: `REDZ.ui.busy(body, promise)` - not on the `<table>`, which cannot hold an overlay.

## Tokens

From [`css/components/table.css`](https://github.com/redz-tech/REDZ.UI/blob/main/css/components/table.css). It declares `--redz-table-head-border`, `--redz-table-head-weight`, `--redz-row-tint`, `--redz-row-mark` on its root, never on rows or items.

It reads the theme's `--redz-space-8`, `--redz-row-pad`, `--redz-space-12`, `--redz-border`, `--redz-table-head-bg`, `--redz-bg`, `--redz-table-head-text`, `--redz-text-muted`, `--redz-fs-12`, `--redz-text`, `--redz-bg-page`, `--redz-border-strong`, `--redz-row-hover`, `--redz-primary`, `--redz-radius-12`, `--redz-space-16`, `--redz-font-mono`, `--redz-space-4`, `--redz-danger-subtle`, `--redz-danger`, `--redz-warning-subtle`, `--redz-warning`, `--redz-primary-subtle`.

## From Bootstrap 5.3

| Bootstrap 5.3 | REDZ.UI | Change | Note |
| --- | --- | --- | --- |
| `caption-top` | - | missing |  |
| `table-dark` | - | review | row tones are danger, warning and secondary |
| `table-hover` | - | remove | every table lights its row under the pointer; table-static keeps one still |
| `table-info` | - | review | row tones are danger, warning and secondary |
| `table-light` | - | review | row tones are danger, warning and secondary |
| `table-primary` | - | review | row tones are danger, warning and secondary |
| `table-responsive` | `table-scroll` | rename | the wrapper scrolls sideways, table-scroll-first holds the first column; or columns hide below md: |
| `table-success` | - | review | row tones are danger, warning and secondary |
