DataTable
Interactive
See DataTable in Storybook for every variant, with live controls.
A dense table with typed columns, optional sorting and clickable rows. Generic over the row type.
import { DataTable, type Column } from "@kairosis/eidos";
interface Run {
id: string;
service: string;
duration: string;
}
const columns: Column<Run>[] = [
{ key: "id", label: "Run", mono: true, sortable: true, width: 90 },
{ key: "service", label: "Service", sortable: true },
{ key: "duration", label: "Duration", mono: true, align: "right" },
];
<DataTable columns={columns} rows={runs} rowKey="id" onRowClick={open} />;
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | Column<T>[] | — | Required |
rows | T[] | — | Required |
rowKey | keyof T | row index | Field to key rows by |
onRowClick | (row: T) => void | — | Makes rows hoverable and clickable |
sortKey | string | — | Currently sorted column |
sortDir | "asc" | "desc" | — | |
onSort | (key: string) => void | — |
Column<T> is { key, label, align?, width?, mono?, sortable?, render? }. render(row) replaces the cell's content.
Guidelines
- Sorting is controlled.
onSortreports intent — it tells you which header was clicked. You reorderrowsand pass backsortKey/sortDir. DataTable never sorts your data, so it can't disagree with the server. - Set
monoon any column holding a data value — IDs, timestamps, durations, counts. It also switches on tabular figures so digits align down the column. - Use
renderfor cells that aren't plain text (aBadgefor status). - Pass
rowKey, or rows fall back to index keys and will re-key on reorder. - Cells truncate at 320px rather than wrapping, keeping row heights uniform.