ComponentsTable
Table
Display data in rows and columns.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
Usage
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@dethink/components";Try the examples, then open the code to use them in your app.
Basic
Caption, header, and body with an end-aligned numeric column.
| Version | Released | Downloads |
|---|---|---|
| 1.4.0 | Jun 2026 | 12,410 |
| 1.3.2 | May 2026 | 31,876 |
| 1.3.1 | May 2026 | 8,204 |
Show sourceexamples/table/basic.tsx
examples/table/basic.tsx
"use client";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@dethink/components";
const releases = [
{ version: "1.4.0", date: "Jun 2026", downloads: "12,410" },
{ version: "1.3.2", date: "May 2026", downloads: "31,876" },
{ version: "1.3.1", date: "May 2026", downloads: "8,204" },
];
export function TableBasic() {
return (
<Table>
<TableCaption>Recent releases and adoption.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Version</TableHead>
<TableHead>Released</TableHead>
<TableHead align="end">Downloads</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{releases.map((release) => (
<TableRow key={release.version}>
<TableCell className="font-mono">{release.version}</TableCell>
<TableCell>{release.date}</TableCell>
<TableCell align="end" className="tabular-nums">
{release.downloads}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}Density
compact for dashboards, comfortable for reading-heavy tables.
| compact | p50 | p99 |
|---|---|---|
| US East | 38 ms | 212 ms |
| EU West | 44 ms | 301 ms |
| comfortable | p50 | p99 |
|---|---|---|
| US East | 38 ms | 212 ms |
| EU West | 44 ms | 301 ms |
Show sourceexamples/table/density.tsx
examples/table/density.tsx
"use client";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@dethink/components";
const rows = [
{ region: "US East", p50: "38 ms", p99: "212 ms" },
{ region: "EU West", p50: "44 ms", p99: "301 ms" },
];
export function TableDensity() {
return (
<div className="grid gap-6 lg:grid-cols-2">
{(["compact", "comfortable"] as const).map((density) => (
<Table key={density} density={density}>
<TableHeader>
<TableRow>
<TableHead>{density}</TableHead>
<TableHead align="end">p50</TableHead>
<TableHead align="end">p99</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rows.map((row) => (
<TableRow key={row.region}>
<TableCell>{row.region}</TableCell>
<TableCell align="end" className="tabular-nums">
{row.p50}
</TableCell>
<TableCell align="end" className="tabular-nums">
{row.p99}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
))}
</div>
);
}Examples that combine components for common tasks.
Invoice
Numeric columns right-aligned with tabular numerals, a muted tone for the secondary usage line, and the computed total in a real TableFooter.
| Item | Qty | Unit | Amount |
|---|---|---|---|
| Team plan · 12 seats | 12 | $29.00 | $348.00 |
| SSO add-on | 1 | $99.00 | $99.00 |
| Usage overageper request | 41,000 | $0.00 | $32.80 |
| Total due | $479.80 | ||
Show sourceexamples/table/recipe-invoice.tsx
examples/table/recipe-invoice.tsx
"use client";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@dethink/components";
const lines = [
{ item: "Team plan · 12 seats", qty: 12, unit: 29, note: "" },
{ item: "SSO add-on", qty: 1, unit: 99, note: "" },
{
item: "Usage overage",
qty: 41_000,
unit: 0.0008,
note: "per request",
muted: true,
},
];
const currency = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});
/**
* Semantic table anatomy carrying real invoice structure: numeric columns
* right-aligned with tabular numerals, a muted tone for secondary lines,
* and the total in a real TableFooter.
*/
export function TableRecipeInvoice() {
const total = lines.reduce((sum, line) => sum + line.qty * line.unit, 0);
return (
<Table>
<TableCaption placement="top">
Invoice #2026-0714 — July 2026
</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Item</TableHead>
<TableHead align="end">Qty</TableHead>
<TableHead align="end">Unit</TableHead>
<TableHead align="end">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{lines.map((line) => (
<TableRow key={line.item} tone={line.muted ? "muted" : "default"}>
<TableCell>
{line.item}
{line.note ? (
<span className="text-muted-foreground ml-2 text-xs">
{line.note}
</span>
) : null}
</TableCell>
<TableCell align="end" className="tabular-nums">
{line.qty.toLocaleString("en-US")}
</TableCell>
<TableCell align="end" className="tabular-nums">
{currency.format(line.unit)}
</TableCell>
<TableCell align="end" className="tabular-nums">
{currency.format(line.qty * line.unit)}
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3} className="font-medium">
Total due
</TableCell>
<TableCell align="end" className="font-medium tabular-nums">
{currency.format(total)}
</TableCell>
</TableRow>
</TableFooter>
</Table>
);
}Every part renders its native table element, so standard table attributes apply throughout.
| Prop | What it does | Default |
|---|---|---|
Table — density"compact" | "default" | "comfortable" | Row height and padding scale for the whole table. | "default" |
Table — containerClassNamestring | Styles the scroll container that keeps wide tables from breaking the page. | Not set |
TableHead / TableCell — align"start" | "center" | "end" | Column alignment; use end for numeric columns. | "start" |
TableRow — tone"default" | "muted" | Muted background for secondary rows. | "default" |
TableRow — selected / hoverableboolean | Selected background and hover treatment via data attributes. | Not set |
TableCaption — placement"top" | "bottom" | Where the caption renders; it names the table either way. | "bottom" |
AnatomyHeader | Body | Footer | Row | Head | Cell | Caption | Real table elements underneath — semantics, keyboard behavior, and screen-reader navigation are native. | Not set |