DataTable
Rows per page
Showing 1-25 of 25
DataTable
A flexible data table with sorting, filtering, pagination, row selection, column visibility, and CSV/XLSX export.
Usage
import { DataTable, ColumnMetadata } from "@/components/ui/data-table"
type Row = { name: string; status: string; cost: number }
const columnsMetadata = [
{ columnId: "name", title: "Name", type: "text", sortable: true, filters: { text: true } },
{ columnId: "status", title: "Status", type: "text", inferOptions: true, filters: { checkboxSearch: { multiple: false } } },
{ columnId: "cost", title: "Cost", type: "number", sortable: true, filters: { number: true } },
] as const satisfies ColumnMetadata<Row>[]
<DataTable<Row>
columnsMetadata={columnsMetadata}
data={data}
bordered
enablePagination
paginationDisplayTop
/>DataTable props
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | TData[] | — | The row data array. |
| columnsMetadata | readonly ColumnMetadata<TData>[] | — | Declarative column config. When provided, columns are built automatically from this. |
| persistColumnOrder | boolean | false | Persists column visibility/order to localStorage (requires tableName). |
| tableName | string | — | Base filename for CSV/XLSX exports (e.g. "usage_overview" → usage_overview-2026-03-16.csv). Also used as the localStorage key when persistColumnOrder is true. |
| enableRowSelection | boolean | false | Enables per-row checkboxes and bulk editor toolbar. |
| enableRowActions | boolean | false | Renders an actions column at the end of each row. |
| enablePagination | boolean | true | Enables pagination controls. |
| pageSize | number | 25 | Initial number of rows per page. |
| enablePageSizeSelect | boolean | true | Shows a page-size selector in the pagination bar. |
| paginationDisplayTop | boolean | false | Renders pagination above the table instead of below. |
| language | "en" | "pt" | "en" | UI locale for labels and messages. |
| enableTextSelection | boolean | true | Allows text selection inside cells. Set to false to prevent accidental selection on click. |
| enableFullscreen | boolean | false | Adds a fullscreen toggle button to the toolbar. Opens the table in a fixed overlay covering the entire viewport via a React portal. Press Escape or click the button again to exit. |
| stickyHeader | boolean | false | Floats a copy of the header at the top of the viewport once the real one scrolls out of view, so long tables keep their column labels. Portaled to the body and aligned to the table, so an overflow-hidden ancestor can't clip it. |
| stickyHeaderOffset | number | 16 | Gap in px between the top of the scroll viewport and the floating header. |
| stickyHeaderSortable | boolean | true | Whether the floating header can sort. Set to false to make it labels-only — the arrows still reflect the current sort, they just stop responding to clicks. |
| enableDownload | boolean | true | Shows or hides the Export dropdown button in the toolbar. When false, the CSV/XLSX download options are not rendered. |
| bordered | boolean | false | Wraps the table in a rounded border. |
| tableStyle | "default" | "ghost" | "default" | Visual style preset. "ghost" removes all background colors and row dividers, keeping only the outer border when bordered is true. |
| accentColor | string | — | Accent color applied to active filter button backgrounds, filter value labels, the row-selection indicator bar, and the clear-filters button. Accepts a Tailwind color token (e.g. "blue-600") or any CSS color value (e.g. "#3b82f6"). Defaults to zinc-800. |
| onRowAction | { onAdd?: (row: TData) => void; onEdit?: (row: TData) => void; onDelete?: (row: TData) => void } | — | Callbacks for the per-row action dropdown (requires enableRowActions). Only menu items with a corresponding callback are rendered. |
| onBulkAction | { onEdit?: (rows: TData[]) => void; onDelete?: (rows: TData[]) => void; actions?: DataTableBulkAction<TData>[] } | — | Callbacks for the bulk editor toolbar (requires enableRowSelection). Edit and Delete render only when their callback is given. Use actions — { label, shortcut, action, disabled? } — for a bulk operation that is neither an edit nor a delete: the built-in labels come from locale and cannot be renamed. |
ColumnMetadata fields
| Prop | Type | Default | Description |
|---|---|---|---|
| columnId* | keyof TData & string | — | Key of the row data object this column maps to. |
| title* | string | — | Column header label. |
| type* | "text" | "number" | "date" | — | Data type — drives which filter controls and sort logic are applied. |
| subtitle | string | — | Secondary label shown below the title in the column header. |
| description | string | — | Tooltip text shown on the column header info icon. |
| sortable | boolean | false | Enables click-to-sort on the column header. |
| hideable | boolean | true | Controls whether the column appears in the visibility toggle menu. |
| aligned | "left" | "center" | "right" | "left" | Horizontal alignment of both header and cell content. |
| options | OptionItem[] | — | Explicit list of { value, label } pairs for select/checkbox filters. Alongside inferOptions it becomes a label dictionary instead of the list itself. |
| inferOptions | boolean | false | Auto-derives filter options from the unique values in the data array. Values always come from the data; pass options too to label them, and any value missing from that dictionary keeps its raw text. |
| filters | FilterConfig | — | Which filter controls to activate for this column. See FilterConfig below. |
| formatter | (value: unknown) => ReactNode | — | Custom cell renderer for the display value (e.g. currency, badges). |
| filterValueFormatter | (value: number) => string | — | Formats numeric values shown inside active number/percentage filter pills. |
| cell | (props: CellContext<TData, unknown>) => ReactNode | — | Full TanStack cell render override — use when you need access to the full row context. |
| header | (props: HeaderContext<TData, unknown>) => ReactNode | — | Full TanStack header render override. |
FilterConfig fields
| Prop | Type | Default | Description |
|---|---|---|---|
| text | boolean | — | Debounced free-text search input. Works with type: "text". |
| textColumns | string[] | — | Additional column IDs to search alongside the primary text column. When set, a single input matches any of the listed columns. The placeholder updates automatically to list all searchable column titles. |
| checkbox | boolean | — | Multi-select checkbox filter (arrIncludesSome). Requires options or inferOptions: true. |
| checkboxSearch | boolean | { multiple?: boolean } | — | Checkbox list with a search box. Set multiple: false for single-select (radio-style). Requires options or inferOptions: true. |
| select | boolean | — | Single-value dropdown filter. Requires options or inferOptions: true. |
| number | boolean | — | Condition + value filter (e.g. > 100, between 50–200). Works with type: "number". |
| percentage | boolean | — | Dual-thumb range slider from 0–100. Works with type: "number" where values are percentages. |
| date | boolean | — | Date range picker (start/end). Works with type: "date". |