A native <table> laid out with grid and subgrid,
so every row shares the same columns.
Standalone
<link rel="stylesheet" href="https://esm.sh/@erikt/ui/table.css" />
Default
Column count is detected automatically from the header row. All rows
inherit the same grid via subgrid.
| Name | Role | Status |
|---|---|---|
| Alice | Engineer | Active |
| Bob | Designer | Away |
| Carol | Manager | Active |
| 3 members | 2 active |
<table>
<caption>
Team members
</caption>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>Engineer</td>
<td>Active</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>3 members</td>
<td></td>
<td>2 active</td>
</tr>
</tfoot>
</table>
Custom columns
Set --cols on the table to override the default equal
widths with any grid template value.
| Description | Date | Category | Amount |
|---|---|---|---|
| Monthly subscription | Mar 1 | Software | $12.00 |
| Office supplies | Mar 8 | Equipment | $34.50 |
| Team lunch | Mar 15 | Food | $87.20 |
<table style="--cols: 2fr 1fr 1fr 80px">
<thead>
<tr>
<th>Description</th>
<th>Date</th>
<th>Category</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Monthly subscription</td>
<td>Mar 1</td>
<td>Software</td>
<td>$12.00</td>
</tr>
</tbody>
</table>
Overflow
Tables scroll horizontally when their content exceeds the container
width. No wrapper needed. Add nowrap to keep each cell
on one line, so the table scrolls instead of wrapping text.
| Name | Department | Location | Start date | Status | |
|---|---|---|---|---|---|
| Alice | alice@example.com | Engineering | New York | Jan 12, 2022 | Active |
| Bob | bob@example.com | Design | London | Mar 4, 2023 | Away |
| Carol | carol@example.com | Management | Berlin | Sep 1, 2021 | Active |
<table class="nowrap">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Department</th>
<th>Location</th>
<th>Start date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>alice@example.com</td>
<td>Engineering</td>
<td>New York</td>
<td>Jan 12, 2022</td>
<td>Active</td>
</tr>
</tbody>
</table>
With actions
A dropdown in the last column gives each row its own actions.
| Name | Role | Status | Actions |
|---|---|---|---|
| Alice | Engineer | Active |
|
| Bob | Designer | Away |
|
| Carol | Manager | Active |
|
<table>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>Engineer</td>
<td>Active</td>
<td>
<button class="ghost square" popovertarget="actions-1">
<svg><!-- ellipsis icon --></svg>
</button>
<div id="actions-1" popover>
<menu>
<li><button class="ghost">Edit</button></li>
<li><button class="ghost">Duplicate</button></li>
<li><hr /></li>
<li><button class="ghost destructive">Remove</button></li>
</menu>
</div>
</td>
</tr>
</tbody>
</table>
Zebra
Add class="zebra" to the table to alternate row
backgrounds.
| Name | Role | Status |
|---|---|---|
| Alice | Engineer | Active |
| Bob | Designer | Away |
| Carol | Manager | Active |
| David | Engineer | Active |
<table class="zebra">
...
</table>
Align left
The last column is right-aligned by default. Add
class="align-left" to the table to align it left like
the other columns.
| Name | Role | Status |
|---|---|---|
| Alice | Engineer | Active |
| Bob | Designer | Away |
| Carol | Manager | Active |
<table class="align-left">
...
</table>
API reference
| Type | Classes / attributes | What it does |
|---|---|---|
| Alignment | .align-left |
Left aligns the last column too |
| Stripes | .zebra |
Shades every other body row |
| Wrapping | .nowrap |
Keeps each cell on one line, so wide tables scroll |
| Columns | --cols: 2fr 1fr 1fr |
Column widths, instead of equal columns |