# DataTable

> Records to sort, select and hide columns in, on TanStack Table v9, rendered as a real table. Sorting says its order to screen readers, every row's checkbox names the row, and past 500 rows only the rows in view are rendered. It carries its own states under the header: skeleton rows in the table's shape while loading, an EmptyState when there is nothing yet, another when the filters hide everything, with a button to clear them, and an error with a retry in place of rows that would read as current. Below 640px, show the same data as ListRows.

Section: Data. Docs: https://entrepta.vercel.app/docs/components/data-table

## Install

```bash
npx @entrepta/cli@latest add data-table
```

Files: `data/data-table.tsx`, `data/table.tsx`, `primitives/checkbox.tsx`, `feedback/skeleton.tsx`, `lib/icon.tsx`, `primitives/icon-tile.tsx`, `feedback/empty-state.tsx`, `primitives/button.tsx`, `primitives/button-variants.ts`.
npm packages: `class-variance-authority`, `@phosphor-icons/react`, `@radix-ui/react-slot`, `@tanstack/react-table`, `@tanstack/react-virtual`.
Comes with: `table`, `checkbox`, `skeleton`, `icon-lib`, `icon-tile`, `empty-state`, `button`.

## Usage

```tsx
import { DataTable, dataTableColumns } from "@/components/entrepta/data-table"

const col = dataTableColumns<Entry>()
const columns = col.columns([
  col.accessor("date", { header: "date" }),
  col.accessor("item", { header: "item" }),
  col.accessor("amount", {
    header: "amount",
    cell: (info) => <Amount value={info.getValue()} tone="auto" />,
  }),
])

<DataTable
  aria-label="entries"
  data={entries}
  columns={columns}
  getRowId={(entry) => entry.id}
  numeric={["amount"]}
  selectable
  rowLabel={(entry) => `Select ${entry.item}`}
  loading={isLoading}
  error={failed ? { description: failed.message, onRetry: refetch } : null}
  filtered={filters.length > 0}
  onClearFilters={clearFilters}
  empty={{ title: "No entries yet", action: <Button>add an entry</Button> }}
/>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `data / columns` | `T[] / columns from dataTableColumns<T>()` | - | The records, and the columns built with the typed helper |
| `numeric` | `string[]` | - | Column ids aligned right in tabular figures |
| `sorting / onSortingChange / manualSorting` | `SortingState / OnChangeFn / boolean` | - | Controlled sorting; manual when the server sorts |
| `selectable / rowSelection / rowLabel` | `boolean / RowSelectionState / (row) => string` | - | A checkbox per row, named by rowLabel, and one for all |
| `columnVisibility` | `ColumnVisibilityState` | - | Which columns show |
| `loading` | `boolean` | false | Skeleton rows in the table's shape, numbers on the right |
| `empty` | `{ title?, description?, action?, icon? }` | - | No rows yet: what is missing and the one thing to do |
| `filtered / onClearFilters` | `boolean / () => void` | - | The filters hide every row: says so and offers to clear them |
| `error` | `{ title?, description?, onRetry? } \| null` | - | The rows did not load: announced, with a retry, instead of the rows |
| `labels` | `{ emptyTitle?, filteredTitle?, clearFilters?, errorTitle?, retry?, … }` | - | The words of the built-in states, for another language |
| `maxHeight` | `number` | - | Scrolls in its box; required to virtualize more than 500 rows |
