Browse documentation
On this page
Table
Tables are styled directly, with an optional .striped modifier for
alternating row backgrounds.
| # | Name | Role |
|---|---|---|
| 1 | Alex Doe | Engineer |
| 2 | Sam Ray | Designer |
Show HTML
<table>
<caption>Project team and roles</caption>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Role</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Alex Doe</td>
<td>Engineer</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Sam Ray</td>
<td>Designer</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr><th scope="col">#</th><th scope="col">Name</th><th scope="col">Role</th></tr>
</thead>
<tbody>
<tr><th scope="row">1</th><td>Alex Doe</td><td>Engineer</td></tr>
</tbody>
</table>
Caption #
<caption> is the native way to give a table an accessible name, and the one
WCAG guidance prefers over a heading placed outside the table — the name
travels with the table instead of depending on proximity.
<table>
<caption>Project team and roles</caption>
…
</table>
Cirth aligns it to start like the cells beneath it, sets it in
--cirth-muted-color, and puts half a rhythm step between it and the header
row. It stays above the table; caption-side: bottom is yours to set if you
want it underneath.
Striped #
| # | Name | Role |
|---|---|---|
| 1 | Alex Doe | Engineer |
| 2 | Sam Ray | Designer |
| 3 | Jo Park | Manager |
Show HTML
<table class="striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Role</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Alex Doe</td>
<td>Engineer</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Sam Ray</td>
<td>Designer</td>
</tr>
<tr>
<th scope="row">3</th>
<td>Jo Park</td>
<td>Manager</td>
</tr>
</tbody>
</table>
<table class="striped">…</table>
.striped is only available in the default build with classes enabled.
Behavior #
border-collapse: collapse, full width, left aligned cells (text-align: start, so it flips correctly in[dir="rtl"]).- Cell padding is
calc(var(--cirth-spacing) / 2) var(--cirth-spacing), with a bottom border in--cirth-table-border-color. tfootcells get a top border instead of a bottom one.thead/tfootcells are bolder (--cirth-font-weight-semibold) with a thicker border.<caption>is aligned tostartin the muted ink, with half a rhythm step below it.
A wide table, scrollable and operable #
A table wider than its column has to scroll, and a scroll container is only operable if a keyboard can reach it. This is the pattern — four attributes, and all four are load-bearing:
<div class="overflow-auto"
tabindex="0"
role="region"
aria-label="Project team and roles">
<table>…</table>
</div>
.overflow-automakes it scroll, and paints the focus ring (Overflow auto).tabindex="0"makes the container itself focusable, which is what lets a keyboard user scroll it at all (WCAG 2.1.1). This is what axe'sscrollable-region-focusablerule reports when it is missing.role="region"plusaria-labelgive that new stop in the tab order a name, so it is announced as something rather than as an unlabelled group.
There is no component for this and there does not need to be one: it is a
<div> with a utility and three attributes. Cirth ships the scroll container
and its focus ring; naming the region is the page's job, because only the
page knows what the table is. Give each scrollable region on a page a
distinct name.
This site applies it to every table in its own documentation, from
docs/eleventy.config.js.