Skip to content
Dethink Components

ComponentsTable

Table

Display data in rows and columns.

On this page

Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.

View registry files

Implemented with React and browser APIs, without an additional behavior or rendering library.

Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.

Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.

Import 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.

Recent releases and adoption.
VersionReleasedDownloads
1.4.0Jun 202612,410
1.3.2May 202631,876
1.3.1May 20268,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.

compactp50p99
US East38 ms212 ms
EU West44 ms301 ms
comfortablep50p99
US East38 ms212 ms
EU West44 ms301 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.

Invoice #2026-0714 — July 2026
ItemQtyUnitAmount
Team plan · 12 seats12$29.00$348.00
SSO add-on1$99.00$99.00
Usage overageper request41,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.

Table anatomy
PropWhat it doesDefault
Table — density"compact" | "default" | "comfortable"Row height and padding scale for the whole table."default"
Table — containerClassNamestringStyles 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 / hoverablebooleanSelected 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 | CaptionReal table elements underneath — semantics, keyboard behavior, and screen-reader navigation are native.Not set