# Data table (goodtabs UI)

A table with sortable columns and row selection with a select all checkbox.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/data-table.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/data-table`

## Usage

```tsx
import { DataTable, type DataTableColumn } from "@/components/ui/data-table"

<DataTable label="Invoices" columns={columns} rows={invoices} getRowId={(r) => r.id} selectable />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| columns | `DataTableColumn<T>[]` |  | Column definitions: key, header, align, sortable, sortValue, render, className. |
| rows | `T[]` |  | The data. Sorting never mutates it. |
| getRowId | `(row: T) => string` |  | Stable id per row. Selection is stored as ids. |
| label | `string` |  | Accessible name for the table. |
| selectable | `boolean` | `false` | Adds the checkbox column and the count footer. |
| selected | `string[]` |  | Controlled selection. Pair with onSelectedChange. |
| defaultSelected | `string[]` | `[]` | Initial selection when uncontrolled. |
| onSelectedChange | `(ids: string[]) => void` |  | Called with the next list of selected ids. |
| defaultSort | `{ key; direction } | null` | `null` | Initial sort column and direction. |

## When to use

- Lists where people pick several rows to act on: invoices, members, files
- Short tables that need sorting without a server round trip

## When not to use

- Read only lists with no selection: simple-table is lighter
- Thousands of rows: paginate or virtualise on the server

## Notes for agents

- getRowId and render are functions, so the component that renders DataTable must be a client component
- Selection is by row id, so it survives re-sorting
- The header checkbox selects every row and shows a dash when only some are selected
- Clicking a sorted header cycles ascending, descending, then unsorted

Docs: https://ui.goodtabs.co/components/data-table