Table
Shows rows of data in columns, read-only. For sorting, selection and row actions, use Data table.
| Opportunity name | Account name | Stage | Amount |
|---|---|---|---|
| Acme - 1,200 Widgets | Acme | Prospecting | $140,000 |
| Global Media - 400 Licenses | Global Media | Negotiation | $62,500 |
| Edge Communications - Upgrade | Edge Communications | Closed Won | $27,000 |
| Burlington Textiles - 200 Seats | Burlington Textiles | Proposal | $235,000 |
| Total | $464,500 | ||
Installation
The CLI installs the Radix or Base UI file to match your project.
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- People read and compare records in rows and columns, like a related list or a report.
- The data is read-only, or each row has a link or a simple action.
Don't use it
- People sort, select rows for a bulk action, resize columns, use row actions or load more rows, and you want that handled for you. Use Data Table.
- People edit cells in place or move between cells with the arrow keys. Neither Table nor Data Table does that yet.
- The data is one record's fields. Use a definition list or a Card.
- The content is a layout, not data.
Usage
Table
├── TableCaption
├── TableHeader
│ └── TableRow
│ └── TableHead
├── TableBody
│ └── TableRow
│ └── TableCell
└── TableFooter
└── TableRow
└── TableCellimport {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"<Table aria-label="Contacts">
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Ada Lovelace</TableCell>
<TableCell>ada@acme.example</TableCell>
</TableRow>
</TableBody>
</Table>Two patterns come from attributes. A Checkbox straight inside the first TableHead and each row's first TableCell makes a selection column, and data-state="selected" on a TableRow draws it selected, as the Selection column example shows. A TableHead with aria-sort and a plain <button> inside becomes a sortable header: give the button an ArrowDownIcon, which turns for ascending and hides for none. The Sortable headers example sorts the rows itself.
<TableHead aria-sort="ascending">
<button type="button">
Name
<ArrowDownIcon />
</button>
</TableHead>Examples
Selection column
A checkbox in each row's first cell and one in the header, and the checked row is drawn selected with `data-state="selected"` on `TableRow`.
| Name | Title | ||
|---|---|---|---|
| Ada Lovelace | Chief Analyst | ada@acme.example | |
| Grace Hopper | VP Engineering | grace@acme.example | |
| Alan Turing | Head of Research | alan@acme.example |
Sortable headers
Headers with `aria-sort` and a `<button>`, sorted by name. Click a header to sort by it.
| Ada Lovelace | Chief Analyst | ada@acme.example |
| Alan Turing | Head of Research | alan@acme.example |
| Grace Hopper | VP Engineering | grace@acme.example |
API reference
| Part | Built on |
|---|---|
Table | <table> (opens in a new tab) |
TableHeader | <thead> (opens in a new tab) |
TableBody | <tbody> (opens in a new tab) |
TableFooter | <tfoot> (opens in a new tab) |
TableRow | <tr> (opens in a new tab) |
TableHead | <th> (opens in a new tab) |
TableCell | <td> (opens in a new tab) |
TableCaption | <caption> (opens in a new tab) |
SLDS mapping
Table is slds-table slds-table_bordered as lightning-datatable draws it, so it matches Data Table: no slds-table_cell-buffer, and a line under the header. TableHeader cells are the header row, TableRow takes slds-is-selected from data-state="selected", a cell holding a checkbox is lightning-datatable's selection column, and a TableHead with aria-sort is slds-is-sortable with its button as slds-th__action and its arrow as slds-is-sortable__icon. TableFooter and TableCaption have no SLDS counterpart: the footer borrows the header's look, the caption is weak text under the table.
Known gaps:
- Striping, fixed layout, column borders, resizing and inline editing aren't styled. Data Table adds a fixed layout and resizable columns.
- The header checkbox can show SLDS's mixed state: pass
checked="indeterminate"in Radix projects andindeterminatein Base UI projects.
Accessibility
- Name the table with a
TableCaptionor anaria-labelonTable. - Put column headers in
TableHeader. For a row header, useTableHeadwithscope="row"in a body row. data-state="selected"only changes the look. Select rows with checkboxes, named by their row ("Select Ada Lovelace") and "Select all rows" in the header, so the state reaches assistive tech.- Keep
aria-sorton every sortable header, with"none"on the unsorted ones, so screen readers hear which column is sorted and how. The button inside names the column.
Responsive behavior
- The table fills its container. When the columns don't fit, the container scrolls sideways; the page doesn't.
- Cells don't wrap. Add
whitespace-normalto a cell to let long text wrap.
Performance
- Every row renders. For more than a few hundred rows, page the data with Pagination, or use Data Table, which can render only the rows in view.
Rules
- Set
data-state="selected"for a selected row. A background class pins one theme's color. - Put
Checkboxdirectly in the cell, not in a wrapper, or a row's box no longer sits on the text line. - Put a plain
<button>in a sortable header, neverButton: its own height, padding and hover fight the header's. - Align numbers with
text-endon their head and cells. - Don't add borders, stripes or padding classes; the tokens carry each theme's table.