## Data Table (S—020)

A typed, sortable, searchable table with row selection, bulk actions and pagination.

- URL: https://sundaeui.dev/components/data-table
- Category: Cards & data visualization · Art direction: Understated
- Access: Free (no account needed)
- Stack: React 18+, TypeScript, Tailwind CSS; dependencies: none
- Install: `npx shadcn@latest add https://sundaeui.dev/r/data-table.json`
- Tags: data-grid, dashboard, tailwind, pagination, sorting, table, react

The table most products need on day one. Columns are typed against your row shape, cells can render anything, and any column can be sortable: click once for ascending, twice for descending, and a third time to clear. Search filters on the fields you choose and resets to the first page.
Selecting rows swaps the search toolbar for a bulk-action bar, with your own actions such as mark paid or delete. The header checkbox selects the current page and shows an indeterminate state when only some rows are selected. An empty search shows a clear-search action instead of a blank table.
Use it for invoices, users, orders and logs, up to a few thousand rows held in the client. For server-paginated or very large datasets, keep the visual layer and move filtering and sorting into your query.

### Usage

```tsx
import { DataTable } from '@/components/sundae/data-table'

<DataTable
  caption="Invoices"
  rows={invoices}               // { id: string, ... }[]
  searchKeys={['id', 'customer']}
  columns={[
    { key: 'id', header: 'Invoice', sortable: true },
    { key: 'customer', header: 'Customer', sortable: true },
    { key: 'amount', header: 'Amount', sortable: true, align: 'right', cell: (r) => format(r.amount) },
  ]}
  bulkActions={(selected, clear) => <button onClick={() => archive(selected).then(clear)}>Archive</button>}
/>
```

### Props

- `rows` (`T[] (with id: string)`, required): Data rows.
- `columns` (`Column<T>[]`, required): { key, header, cell?, sortable?, align?, hideOnMobile? }.
- `searchKeys` (`(keyof T)[]`): Fields the search box matches.
- `pageSize` (`number`, default `8`): Rows per page.
- `selectable` (`boolean`, default `true`): Adds row checkboxes.
- `bulkActions` (`(selected, clear) => ReactNode`): Toolbar content shown while rows are selected.
- `emptyMessage` (`string`): Shown when nothing matches.
- `caption` (`string`, default `'Table'`): Accessible table caption.

### Accessibility

- A real <table> with a caption, column scopes and aria-sort on sortable headers.
- Sort controls are buttons inside the headers. Selection uses labelled checkboxes, with an indeterminate state on the header.
- Pagination is a labelled navigation landmark.
