# DataTable _(no submodules)_ - data-table.variants — `dataTableVariants`, `dataTab… - [data-table.variants](./data-table.variants.md) — `dataTableVariants`, `dataTablePaginationVariants`, and `dataTableSortHeaderVariants` drive the chassis `` o… - data-table.variants — `dataTableVariants`, `dataTab… - [data-table.variants](./data-table.variants.md) — `dataTableVariants`, `dataTablePaginationVariants`, and `dataTableSortHeaderVariants` drive the chassis `` o… - data-table.variants — `dataTableVariants`, `dataTab… - [data-table.variants](./data-table.variants.md) — `dataTableVariants`, `dataTablePaginationVariants`, and `dataTableSortHeaderVariants` drive the chassis `` o… - data-table.variants — `dataTableVariants`, `dataTab… - [data-table.variants](./data-table.variants.md) — `dataTableVariants`, `dataTablePaginationVariants`, and `dataTableSortHeaderVariants` drive the chassis `` o… - [data-table.variants](./data-table.variants.md) — `dataTableVariants`, `dataTablePaginationVariants`, and `dataTableSortHeaderVariants` drive the chassis `` o… ## Purpose `` is the chassis headless data-table built on `@tanstack/react-table` (v8) and the chassis `` family. It is a **suaveplan-only addition** — shadcn does not ship `data-table` as a registry item upstream (per Wave 3a's reconciliation finding #7); shadcn's docs treat data-tables as recipes consumers build on top of the `
` primitive. The chassis exposes `` as a discrete component so consumers do not hand-roll sorting / pagination / selection / empty-state treatment per surface. The component is generic over `TData` (the row shape) and `TValue` (the column value union, defaults to `unknown`). Consumers build column definitions with the re-exported `createColumnHelper` from `@tanstack/react-table`. Every chassis-rendered string (no-results, pagination, rows-per-page, selection summary) flows through the active i18n via `t()` calls keyed on bundled `react-ui.dataTable.*` translation keys. The `selected` key uses ICU plural so the count agrees with the active locale's plural rules — Welsh's six-form scale is bundled. ## Features - Built on TanStack Table v8 — the de-facto headless table for React. - Sortable columns — click any sortable column header to toggle asc / desc / none; the header button shows a chevron icon indicating the active sort direction. - Pagination — `pageSize` defaults to 10 rows; previous / next buttons disable at the boundaries. - Row selection (opt-in via `enableRowSelection`) — chassis renders a selection summary using ICU plural translation. - Empty state — when no rows match, the chassis renders the bundled `react-ui.dataTable.noResults` message in a single full-width row. - Stable row keys via `getRowId` (recommended) — without it, TanStack uses array-index keys which collide on re-order. - `data-state="selected"` on selected rows so chassis `` hover / selected styling activates automatically. - Re-exports `createColumnHelper` so consumers don't need to add `@tanstack/react-table` as a direct dep. ## Usage: Basic Example ```tsx import { createColumnHelper, DataTable } from "@suaveplan/react-ui"; interface Invoice { readonly id: string; readonly invoice: string; readonly status: string; readonly amount: number; } const columnHelper = createColumnHelper(); const COLUMNS = [ columnHelper.accessor("invoice", { header: "Invoice" }), columnHelper.accessor("status", { header: "Status" }), columnHelper.accessor("amount", { header: "Amount", cell: (info) => `$${info.getValue().toFixed(2)}`, }), ]; export function InvoiceDataTable({ data }: { data: Invoice[] }) { return ( columns={COLUMNS} data={data} getRowId={(row) => row.id} /> ); } ``` ## Usage: Advanced Example ```tsx import { createColumnHelper, DataTable } from "@suaveplan/react-ui"; interface User { readonly id: string; readonly name: string; readonly email: string; readonly role: "admin" | "member"; } const columnHelper = createColumnHelper(); const COLUMNS = [ columnHelper.display({ id: "select", header: "", cell: ({ row }) => ( ), }), columnHelper.accessor("name", { header: "Name", enableSorting: true }), columnHelper.accessor("email", { header: "Email", enableSorting: false }), columnHelper.accessor("role", { header: "Role", enableSorting: true }), ]; export function UserDataTable({ users }: { users: User[] }) { return ( columns={COLUMNS} data={users} getRowId={(row) => row.id} enableRowSelection pageSize={5} initialSorting={[{ id: "name", desc: false }]} /> ); } ``` ## API Reference ### `>` | Prop | Type | Default | Description | |---|---|---|---| | `columns` | `ReadonlyArray>` | — | Column definitions; build with `createColumnHelper()`. | | `data` | `ReadonlyArray` | — | The rows to render. Must be stable identity-wise (use `useMemo` on the consumer side). | | `getRowId` | `(row: TData, index: number) => string` | _undefined_ | Stable row id for selection / keying. Recommended. | | `enableRowSelection` | `boolean` | `false` | When true, renders a selection summary using ICU plural translation. | | `pageSize` | `number` | `10` | Rows per page. | | `initialSorting` | `SortingState` | `[]` | Initial sort state. | | `noResultsKey` | `TranslationKey` | `react-ui.dataTable.noResults` | Empty-state message. | | `rowsPerPageKey` | `TranslationKey` | `react-ui.dataTable.rowsPerPage` | Pagination footer label. | | `selectedKey` | `TranslationKey` | `react-ui.dataTable.selected` | ICU-plural selection summary; receives `{ count }`. | | `previousKey` | `TranslationKey` | `react-ui.dataTable.previous` | Previous-page button label. | | `nextKey` | `TranslationKey` | `react-ui.dataTable.next` | Next-page button label. | ### `createColumnHelper()` Re-exported from `@tanstack/react-table`. Returns a builder with `accessor`, `display`, and `group` methods for typed column definitions. #### Errors The DataTable component calls `useTranslation()` to resolve the chassis-rendered translation keys. It MUST render inside a `` / ``; otherwise `useTranslation` throws. ## Implementation Notes - The component is generic over `TData` and `TValue` so consumers get full type-safety on column definitions and cell renderers. The cast to `ColumnDef[]` inside `useReactTable` is a TanStack ergonomics workaround — TanStack's `data` accepts `TData[]` but its `columns` slot accepts a value-erased shape, so the chassis re-asserts the typed shape at the boundary. - The `selected` plural translation includes the Welsh six-form scale (`zero | one | two | few | many | other`) so the count agrees with the active locale's plural rules. Other locales (`en-GB`, `zh-CN`, `ar-AE`, `ru-RU`) use their respective plural categories from the bundled JSON. - `getRowId` is strongly recommended even when `data` items contain an `id` field — without a stable getter, TanStack uses array index keys, which collide when consumers reorder the data array. The chassis does NOT default `getRowId` to `(row) => row.id` because not every `TData` shape has an `id` field. - The pagination controls are intentionally bare `