Data Table
Table with columns as data: search across every column, sortable headers, checkbox selection that survives paging, a ⋯ menu per row, bulk actions in the toolbar and pagination. Built from Table, SearchInput, Checkbox, DropdownMenu, Pagination and Empty.
| Actions | |||
|---|---|---|---|
Wade Howard | 4,623 | ||
Leslie Warren | 4,595 | ||
Guy Williamson | 4,218 | ||
Esther Howard | 4,190 | ||
Kristin Williamson | 3,785 | ||
Cameron Howard | 3,757 |
1–6 of 27
"use client";import { Trash2 } from "lucide-react";import { Button } from "@/components/ui/button";import { type DataTableColumn, DataTable } from "@/components/ui/data-table";import { DropdownMenuItem } from "@/components/ui/dropdown-menu";type Member = { id: string; name: string; messages: number };const columns: DataTableColumn<Member>[] = [ { id: "name", header: "Member", accessor: (m) => m.name, sortable: true }, { id: "messages", header: "Messages", accessor: (m) => m.messages, sortable: true, className: "text-right tabular-nums", },];export function MembersDataTable({ members, onKick,}: { members: Member[]; onKick: (ids: string[]) => void;}) { return ( <DataTable label="Members" data={members} columns={columns} getRowId={(m) => m.id} rowLabel={(m) => m.name} defaultSort={{ id: "messages", dir: "descending" }} selectable toolbar={(selected) => selected.length > 0 && ( <Button size="sm" variant="destructive" onClick={() => onKick(selected.map((m) => m.id))} > Kick {selected.length} </Button> ) } rowActions={(m) => ( <DropdownMenuItem variant="destructive" onSelect={() => onKick([m.id])}> <Trash2 /> Kick </DropdownMenuItem> )} /> );}<DataTable>
Table with search, sortable columns, row selection, row actions and pagination, all on the client. Columns are data: { id, header, accessor, cell?, sortable? }. For server-driven data, compose Table + Pagination yourself.
columns*DataTableColumn<T>[]Column definitions in display order.
data*T[]Rows; search, sort and paging happen on the client.
getRowId*(row: T) => stringStable id per row; selection is kept by it across pages.
label*stringNames the table, the search box and each row's controls: "Members", "Select Jane".
rowLabel*(row: T) => stringRow name for screen readers, e.g. on its checkbox and ⋯ menu.
defaultSortSortSort at first render.
onSelectionChange(ids: string[]) => voidCalled with every selected row id.
pageSizedefault10numberRows per page.
rowActions(row: T) => ReactNodeItems for the row's ⋯ menu (DropdownMenuItem and friends).
searchabledefaulttruebooleanShow a search field that filters every column.
searchPlaceholderdefault"Search…"stringSearch field placeholder.
selectabledefaultfalsebooleanCheckbox column; selection survives search and paging.
selectionstring[]Controlled selected row ids; pair with
onSelectionChange.stripeddefaultfalsebooleanAlternate row backgrounds.
toolbar(selected: T[]) => ReactNodeRight side of the toolbar; receives the selected rows (bulk actions).
| Prop | Type | Default |
|---|---|---|
columns*Column definitions in display order. | DataTableColumn<T>[] | — |
data*Rows; search, sort and paging happen on the client. | T[] | — |
getRowId*Stable id per row; selection is kept by it across pages. | (row: T) => string | — |
label*Names the table, the search box and each row's controls: "Members", "Select Jane". | string | — |
rowLabel*Row name for screen readers, e.g. on its checkbox and ⋯ menu. | (row: T) => string | — |
defaultSortSort at first render. | Sort | — |
onSelectionChangeCalled with every selected row id. | (ids: string[]) => void | — |
pageSizeRows per page. | number | 10 |
rowActionsItems for the row's ⋯ menu (DropdownMenuItem and friends). | (row: T) => ReactNode | — |
searchableShow a search field that filters every column. | boolean | true |
searchPlaceholderSearch field placeholder. | string | "Search…" |
selectableCheckbox column; selection survives search and paging. | boolean | false |
selectionControlled selected row ids; pair with | string[] | — |
stripedAlternate row backgrounds. | boolean | false |
toolbarRight side of the toolbar; receives the selected rows (bulk actions). | (selected: T[]) => ReactNode | — |
- type Sort
- { id: string; dir: "ascending" | "descending" }
- type DataTableColumn
- { id: string; header: ReactNode; accessor?: (row: T) => string | number; cell?: (row: T) => ReactNode; sortable?: boolean; className?: string; }
* required. Every component also takes className.