Table
Structural table primitives — no logic, just the seam surface. The table is a raised key resting on the canvas; the header is a quiet label rail; rows are separated by hairlines and tint on select. For a data grid with sorting, filtering, pagination and inline edit, use Data Table.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Unpaid | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| Total | $1,200.00 | ||
tsx
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/registry/seam/ui/table"
const invoices = [
{
invoice: "INV-001",
status: "Paid",
method: "Credit Card",
total: "$250.00",
},
{ invoice: "INV-002", status: "Pending", method: "PayPal", total: "$150.00" },
{
invoice: "INV-003",
status: "Unpaid",
method: "Bank Transfer",
total: "$350.00",
},
{
invoice: "INV-004",
status: "Paid",
method: "Credit Card",
total: "$450.00",
},
]
export default function TableDemo() {
return (
<Table aria-label="Recent invoices">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((row) => (
<TableRow key={row.invoice}>
<TableCell className="font-medium">{row.invoice}</TableCell>
<TableCell>{row.status}</TableCell>
<TableCell>{row.method}</TableCell>
<TableCell className="text-right tabular-nums">
{row.total}
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right tabular-nums">$1,200.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}bunx --bun @seamui/cli@latest add tableAPI
| Prop | Type | Default | Description |
|---|---|---|---|
| containerClassName | string | — | Classes for the scrollable region wrapper (the raised surface), separate from the <table>. |
| aria-label | string | — | Names the scroll region so keyboard users landing on it know what it is. |
Exports Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, and TableCaption — each carrying a data-slot and forwarding all native props.
Notes
- When the table is wider than its container the wrapper becomes a focusable
role="region"so it can be scrolled by keyboard, not just pointer — a table that fits adds no extra tab stop. - Set
data-state="selected"on aTableRowto tint it — the row tints rather than embosses, keeping the checkbox as the one embossed token. - These primitives are static (no motion of their own). Animation lives in Data Table, which composes them.
Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.