Table
A compositional data table with sortable columns, striped rows, density sizes, and footer totals.
Rendering Table…
Installation
Copy the source into your project with the CLI. It lands under @/components/ui and is yours to edit.
npx mlola-ui add tableUsage
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
const invoices = [
{ id: "INV-104", status: "Paid", amount: "$240.00" },
{ id: "INV-105", status: "Open", amount: "$1,120.00" },
];
export default function Example() {
return (
<Table>
<TableCaption>Recent invoices</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead align="right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.id}>
<TableCell>{invoice.id}</TableCell>
<TableCell>{invoice.status}</TableCell>
<TableCell numeric>{invoice.amount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}Styling comes from the engine stylesheet and the nearest theme. Set it once at the root:
<html data-theme="graphite" data-mode="light">Examples
Sortable
A sortable header is a button that says how it sorts; aria-sort tells assistive technology.
Rendering Sortable…
With status
Status reads as a word first; the tone only reinforces it.
Rendering With status…
HTML
The markup the example above renders, exactly. It needs no script: write it from any language or template.
<div class="ml-table-container">
<table class="ml-table" data-size="md">
<caption class="ml-table-caption">Recent invoices</caption>
<thead class="ml-table-header">
<tr class="ml-table-row">
<th class="ml-table-head" scope="col" data-align="left">Invoice</th>
<th class="ml-table-head" scope="col" data-align="left">Status</th>
<th class="ml-table-head" scope="col" data-align="right">Amount</th>
</tr>
</thead>
<tbody class="ml-table-body">
<tr class="ml-table-row">
<td class="ml-table-cell" data-align="left">INV-104</td>
<td class="ml-table-cell" data-align="left">Paid</td>
<td class="ml-table-cell" data-align="right" data-numeric="">$240.00</td>
</tr>
<tr class="ml-table-row">
<td class="ml-table-cell" data-align="left">INV-105</td>
<td class="ml-table-cell" data-align="left">Open</td>
<td class="ml-table-cell" data-align="right" data-numeric="">$1,120.00</td>
</tr>
</tbody>
</table>
</div>Options
| Component | Prop | Values | Default |
|---|---|---|---|
Table | size | smmd | md |
TableHead | align | leftcenterright | left |
TableCell | align | leftcenterright | left |
Every prop with a fixed set of values, read from the exported TypeScript types with its doc comment. Open the Code tab above for the rest of the API.
Classes and attributes
A class names each element; data-* and aria-* attributes carry its variant and state. The values listed are the ones the stylesheet draws; the default needs no attribute.
| Class | Attributes |
|---|---|
ml-table-container | — |
ml-table-card | — |
ml-table-toolbar | — |
ml-table | data-size="sm"data-stripe="alternate"data-striped |
ml-table-header | — |
ml-table-head | — |
ml-table-cell | — |
ml-table-body | — |
ml-table-row | data-state="selected" |
ml-table-caption | — |
ml-table-footer | — |
ml-table-sort | — |
ml-table-sort-icon | — |
Accessibility and theming
- Semantic elements, accessible names and state relationships are part of the contract.
- Keyboard, pointer and touch paths are operable; focus stays visible in every theme.
- Light and dark modes pass WCAG AA contrast in all 5 canonical themes.
- Reduced motion and forced colors keep meaning and operation.