Data Table
A powerful and flexible data table component for displaying, filtering, sorting, and paginating tabular data.
"use client";
import { DataTable } from "@/components/data-table";
import { DataTableColumnHeader } from "@/components/data-table-column-header";
import { DataTableToolbar } from "@/components/data-table-toolbar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useDataTable } from "@/hooks/use-data-table";
import type { Column, ColumnDef } from "@tanstack/react-table";
import {
CheckCircle,
CheckCircle2,
DollarSign,
MoreHorizontal,
Text,
XCircle,
} from "lucide-react";
import { parseAsArrayOf, parseAsString, useQueryState } from "nuqs";
import * as React from "react";
interface Project {
id: string;
title: string;
status: "active" | "inactive";
budget: number;
}
const data: Project[] = [
{
id: "1",
title: "Project Alpha",
status: "active",
budget: 50000,
},
{
id: "2",
title: "Project Beta",
status: "inactive",
budget: 75000,
},
{
id: "3",
title: "Project Gamma",
status: "active",
budget: 25000,
},
{
id: "4",
title: "Project Delta",
status: "active",
budget: 100000,
},
];
export function DataTableDemo() {
const [title] = useQueryState("title", parseAsString.withDefault(""));
const [status] = useQueryState(
"status",
parseAsArrayOf(parseAsString).withDefault([]),
);
// Ideally we would filter the data server-side, but for the sake of this example, we'll filter the data client-side
const filteredData = React.useMemo(() => {
return data.filter((project) => {
const matchesTitle =
title === "" ||
project.title.toLowerCase().includes(title.toLowerCase());
const matchesStatus =
status.length === 0 || status.includes(project.status);
return matchesTitle && matchesStatus;
});
}, [title, status]);
const columns = React.useMemo<ColumnDef<Project>[]>(
() => [
{
id: "select",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) =>
table.toggleAllPageRowsSelected(!!value)
}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
size: 32,
enableSorting: false,
enableHiding: false,
},
{
id: "title",
accessorKey: "title",
header: ({ column }: { column: Column<Project, unknown> }) => (
<DataTableColumnHeader column={column} title="Title" />
),
cell: ({ cell }) => <div>{cell.getValue<Project["title"]>()}</div>,
meta: {
label: "Title",
placeholder: "Search titles...",
variant: "text",
icon: Text,
},
enableColumnFilter: true,
},
{
id: "status",
accessorKey: "status",
header: ({ column }: { column: Column<Project, unknown> }) => (
<DataTableColumnHeader column={column} title="Status" />
),
cell: ({ cell }) => {
const status = cell.getValue<Project["status"]>();
const Icon = status === "active" ? CheckCircle2 : XCircle;
return (
<Badge variant="outline" className="capitalize">
<Icon />
{status}
</Badge>
);
},
meta: {
label: "Status",
variant: "multiSelect",
options: [
{ label: "Active", value: "active", icon: CheckCircle },
{ label: "Inactive", value: "inactive", icon: XCircle },
],
},
enableColumnFilter: true,
},
{
id: "budget",
accessorKey: "budget",
header: ({ column }: { column: Column<Project, unknown> }) => (
<DataTableColumnHeader column={column} title="Budget" />
),
cell: ({ cell }) => {
const budget = cell.getValue<Project["budget"]>();
return (
<div className="flex items-center gap-1">
<DollarSign className="size-4" />
{budget.toLocaleString()}
</div>
);
},
},
{
id: "actions",
cell: function Cell() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">Open menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem variant="destructive">
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
size: 32,
},
],
[],
);
const { table } = useDataTable({
data: filteredData,
columns,
pageCount: 1,
initialState: {
sorting: [{ id: "title", desc: true }],
columnPinning: { right: ["actions"] },
},
getRowId: (row) => row.id,
});
return (
<div className="data-table-container">
<DataTable table={table}>
<DataTableToolbar table={table} />
</DataTable>
</div>
);
}
Installation
Install the components and dependencies:
npx [email protected] add "https://diceui.com/r/data-table"
pnpm dlx [email protected] add "https://diceui.com/r/data-table"
yarn dlx [email protected] add "https://diceui.com/r/data-table"
bun x [email protected] add "https://diceui.com/r/data-table"
Wrap your application with the NuqsAdapter
for query state management:
import { NuqsAdapter } from "nuqs/adapters/next/app";
<NuqsAdapter>
<App />
</NuqsAdapter>
Layout
Import the components and compose them together:
import { DataTable } from "@/components/data-table";
import { DataTableToolbar } from "@/components/data-table-toolbar";
import { DataTableAdvancedToolbar } from "@/components/data-table-advanced-toolbar";
import { DataTableFilterList } from "@/components/data-table-filter-list";
import { DataTableSortList } from "@/components/data-table-sort-list";
import { useDataTable } from "@/hooks/use-data-table";
const { table } = useDataTable({
data,
columns,
pageCount,
});
// With standard toolbar
<DataTable table={table}>
<DataTableToolbar table={table}>
<DataTableSortList table={table} />
</DataTableToolbar>
</DataTable>
// With advanced toolbar
<DataTable table={table}>
<DataTableAdvancedToolbar table={table}>
<DataTableFilterList table={table} />
<DataTableSortList table={table} />
</DataTableAdvancedToolbar>
</DataTable>
Sort List
The DataTableSortList
provides a comprehensive way to sort data by multiple columns simultaneously.
Features
- Supports multiple column sorting
- Drag and drop reordering
- Ascending and descending directions
Installation
npx [email protected] add "https://diceui.com/r/data-table-sort-list"
pnpm dlx [email protected] add "https://diceui.com/r/data-table-sort-list"
yarn dlx [email protected] add "https://diceui.com/r/data-table-sort-list"
bun x [email protected] add "https://diceui.com/r/data-table-sort-list"
Filter List
The DataTableFilterList
provides a comprehensive way to filter data with multiple conditions.
Features
- Multiple filter conditions with AND/OR logic
- Drag and drop reordering
- Dynamic operators per field type
Installation
npx [email protected] add "https://diceui.com/r/data-table-filter-list"
pnpm dlx [email protected] add "https://diceui.com/r/data-table-filter-list"
yarn dlx [email protected] add "https://diceui.com/r/data-table-filter-list"
bun x [email protected] add "https://diceui.com/r/data-table-filter-list"
Filter Menu
The DataTableFilterMenu
provides a command palette-style interface for quickly adding and managing filters.
Features
- Command palette-style interface
- Context-aware input fields
- Compact token display
Installation
npx [email protected] add "https://diceui.com/r/data-table-filter-menu"
pnpm dlx [email protected] add "https://diceui.com/r/data-table-filter-menu"
yarn dlx [email protected] add "https://diceui.com/r/data-table-filter-menu"
bun x [email protected] add "https://diceui.com/r/data-table-filter-menu"
Action Bar
The DataTableActionBar
provides a toolbar for the data table when rows are selected.
Features
- Floating action bar
- Customizable actions
- Row selection tracking
Installation
npx [email protected] add "https://diceui.com/r/data-table-action-bar"
pnpm dlx [email protected] add "https://diceui.com/r/data-table-action-bar"
yarn dlx [email protected] add "https://diceui.com/r/data-table-action-bar"
bun x [email protected] add "https://diceui.com/r/data-table-action-bar"
Walkthrough
Define columns with appropriate metadata:
import { Text, CalendarIcon, DollarSign } from "lucide-react";
import { DataTableColumnHeader } from "@/components/data-table-column-header";
const columns = React.useMemo(() => [
{
// Provide an unique id for the column
// This id will be used as query key for the column filter
id: "title",
accessorKey: "title",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Title" />
),
cell: ({ row }) => <div>{row.getValue("title")}</div>,
// Define the column meta options for sorting, filtering, and view options
meta: {
label: "Title",
placeholder: "Search titles...",
variant: "text",
icon: Text,
},
// By default, the column will not be filtered. Set to `true` to enable filtering.
enableColumnFilter: true,
},
], []);
Initialize the table state using the useDataTable
hook:
import { useDataTable } from "@/hooks/use-data-table";
function DataTableDemo() {
const { table } = useDataTable({
data,
columns,
// Pass the total number of pages for the table
pageCount,
initialState: {
sorting: [{ id: "createdAt", desc: true }],
pagination: { pageSize: 10 },
},
// Unique identifier for rows, can be used for unique row selection
getRowId: (row) => row.id,
});
return (
// ... render table
);
}
Pass the table instance to the DataTable
, and DataTableToolbar
components:
import { DataTable } from "@/components/data-table";
import { DataTableToolbar } from "@/components/data-table-toolbar";
import { DataTableSortList } from "@/components/data-table-sort-list";
function DataTableDemo() {
return (
<DataTable table={table}>
<DataTableToolbar table={table}>
<DataTableSortList table={table} />
</DataTableToolbar>
</DataTable>
);
}
For advanced filtering, use the DataTableAdvancedToolbar
component:
import { DataTableAdvancedToolbar } from "@/components/data-table-advanced-toolbar";
import { DataTableFilterList } from "@/components/data-table-filter-list";
import { DataTableFilterMenu } from "@/components/data-table-filter-menu";
function DataTableDemo() {
return (
<DataTable table={table}>
<DataTableAdvancedToolbar table={table}>
<DataTableFilterList table={table} />
<DataTableSortList table={table} />
</DataTableAdvancedToolbar>
</DataTable>
);
}
Alternatively, swap out DataTableFilterList
with DataTableFilterMenu
for a command palette-style interface:
import { DataTableAdvancedToolbar } from "@/components/data-table-advanced-toolbar";
import { DataTableFilterList } from "@/components/data-table-filter-list";
import { DataTableFilterMenu } from "@/components/data-table-filter-menu";
import { DataTableSortList } from "@/components/data-table-sort-list";
function DataTableDemo() {
return (
<DataTable table={table}>
<DataTableAdvancedToolbar table={table}>
<DataTableFilterList table={table} />
<DataTableFilterMenu table={table} />
<DataTableSortList table={table} />
</DataTableAdvancedToolbar>
</DataTable>
);
}
Render an action bar on row selection:
import { DataTableActionBar } from "@/components/data-table-action-bar";
import { CustomTableActions } from "@/components/custom-table-actions";
function DataTableDemo() {
return (
<DataTable
table={table}
actionBar={
<DataTableActionBar table={table}>
{/* Add your custom actions here */}
<CustomTableActions />
</DataTableActionBar>
}
>
<DataTableToolbar table={table} />
</DataTable>
);
}
API Reference
Column Definitions
The column definitions are used to define the columns of the data table.
const columns = React.useMemo<ColumnDef<Project>[]>(() => [
{
// Required: Unique identifier for the column
id: "title",
// Required: Key to access the data, `accessorFn` can also be used
accessorKey: "title",
// Optional: Custom header component
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Title" />
),
// Optional: Custom cell component
cell: ({ row }) => <div>{row.getValue("title")}</div>,
// Optional: Meta options for filtering, sorting, and view options
meta: {
label: "Title",
placeholder: "Search titles...",
variant: "text",
icon: Text,
},
// By default, the column will not be filtered. Set to `true` to enable filtering.
enableColumnFilter: true,
},
{
id: "status",
// Access nested data using `accessorFn`
accessorFn: (row) => row.lineItem.status,
header: "Status",
meta: {
label: "Status",
variant: "select",
options: [
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" },
],
},
enableColumnFilter: true,
},
], []);
Properties
Core configuration options for defining columns.
Prop | Description |
---|---|
id | Required: Unique identifier for the column |
accessorKey | Required: Key to access the data from the row |
accessorFn | Optional: Custom accessor function to access data |
header | Optional: Custom header component with column props |
cell | Optional: Custom cell component with row props |
meta | Optional: Meta options for accessing column metadata |
enableColumnFilter | By default, the column will not be filtered. Set to `true` to enable filtering |
enableSorting | Enable sorting for this column |
enableHiding | Enable column visibility toggle |
Column Meta
Column meta options for filtering, sorting, and view options.
Prop | Description |
---|---|
label | The display name for the column |
placeholder | The placeholder text for filter inputs |
variant | The type of filter to use (`text`, `number`, `select`, etc.) |
options | For select/multi-select filters, an array of options with `label`, `value`, and optional `count` and `icon` |
range | For range filters, a tuple of `[min, max]` values |
unit | For numeric filters, the unit to display (e.g., 'hr', '$') |
icon | The react component to use as an icon for the column |
Filter Variants
Available filter variants for column meta.
Title | Description |
---|---|
text | Text search with contains, equals, etc. |
number | Numeric filters with equals, greater than, less than, etc. |
range | Range filters with minimum and maximum values |
date | Date filters with equals, before, after, etc. |
dateRange | Date range filters with start and end dates |
boolean | Boolean filters with true/false values |
select | Single-select filters with predefined options |
multiSelect | Multi-select filters with predefined options |
Reference the TanStack Table Column Definitions Guide for detailed column definition guide.
useDataTable
A hook for initializing the data table with state management.
Prop | Type | Default |
---|---|---|
initialState? | InitialTableState | - |
defaultColumn? | Partial<ColumnDef<TData, unknown>> | - |
getRowId? | ((originalRow: TData, index: number, parent?: Row<TData> | undefined) => string) | - |
columns | ColumnDef<TData, any>[] | - |
data | TData[] | - |
pageCount | number | - |
startTransition? | TransitionStartFunction | - |
shallow? | boolean | true |
scroll? | boolean | false |
enableAdvancedFilter? | boolean | false |
clearOnDefault? | boolean | false |
throttleMs? | number | 50 |
debounceMs? | number | 300 |
history? | "push" | "replace" | "replace" |
DataTable
The main data table component.
Prop | Type | Default |
---|---|---|
actionBar? | ReactNode | - |
table | Table<TData> | - |
DataTableColumnHeader
Custom header component for columns with sorting.
Prop | Type | Default |
---|---|---|
title | string | - |
column | Column<TData, TValue> | - |
DataTableToolbar
Standard toolbar with filtering and view options.
Prop | Type | Default |
---|---|---|
table | Table<TData> | - |
DataTableAdvancedToolbar
Advanced toolbar with more comprehensive filtering capabilities.
Prop | Type | Default |
---|---|---|
table | Table<TData> | - |
DataTableViewOptions
Controls column visibility and display preferences in the data table.
Prop | Type | Default |
---|---|---|
table | Table<TData> | - |
DataTableSortList
List of applied sorting with ability to add, remove, and modify sorting.
Prop | Type | Default |
---|---|---|
shallow? | boolean | true |
throttleMs? | number | 50 |
debounceMs? | number | 300 |
table | Table<TData> | - |
DataTableFilterList
List of applied filters with ability to add, remove, and modify filters.
Prop | Type | Default |
---|---|---|
shallow? | boolean | true |
throttleMs? | number | 50 |
debounceMs? | number | 300 |
table | Table<TData> | - |
DataTableFilterMenu
Filter menu with ability to add, remove, and modify filters.
Prop | Type | Default |
---|---|---|
shallow? | boolean | true |
throttleMs? | number | 50 |
debounceMs? | number | 300 |
table | Table<TData> | - |
DataTableActionBar
Floating action bar component for actions for selected rows.
Prop | Type | Default |
---|---|---|
container? | Element | DocumentFragment | null | document.body |
visible? | boolean | - |
table | Table<TData> | - |
DataTablePagination
Pagination controls for the data table.
Prop | Type | Default |
---|---|---|
pageSizeOptions? | number[] | [10, 20, 30, 40, 50] |
table | Table<TData> | - |
Accessibility
Keyboard Interactions
Key | Description |
---|---|
F | Opens the filter menu. |
Shift + F | Removes the last applied filter. |
S | Opens the sort menu. |
Shift + S | Removes the last applied sort. |
BackspaceDelete | Removes the focused filter/sort item. Removes the last applied filter/sort when menu trigger is focused. |
Credits
- shadcn/ui - For the initial implementation of the data table.