Data Table
A powerful data table component built on TanStack Table with sorting, filtering, pagination, and row selection.
Features
- Sorting: Click column headers to sort ascending, descending, or clear
- Pagination: Built-in page navigation with configurable rows per page
- Row Selection: Checkbox-based row selection with select all support
- Column Visibility: Toggle column visibility via dropdown
- Column Header Actions: Reusable header component with sort and hide options
- Flexible Columns: Define columns with custom renderers, formatters, and actions
Installation
npx shadcn@latest add @uipath/data-tableThis component requires the following dependencies:
@tanstack/react-table- Table state management and utilitieslucide-react- Iconstable- Base table primitivesbutton- Button componentdropdown-menu- Dropdown menu componentselect- Select component (for rows per page)
Usage
1. Define your columns
"use client"
import type { ColumnDef } from "@/components/ui/data-table"
import { DataTableColumnHeader } from "@/components/ui/data-table"
type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
export const columns: ColumnDef<Payment>[] = [
{
accessorKey: "status",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Status" />
),
},
{
accessorKey: "email",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Email" />
),
},
{
accessorKey: "amount",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Amount" />
),
cell: ({ row }) => {
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(row.getValue("amount"))
return <div className="text-right font-medium">{formatted}</div>
},
},
]2. Render the DataTable
Use the useDataTable hook to manage all table state, then spread it into DataTable:
"use client"
import { DataTable } from "@/components/ui/data-table"
import { useDataTable } from "@/hooks/use-data-table"
import { columns } from "./columns"
export default function PaymentsPage({ data }: { data: Payment[] }) {
const tableState = useDataTable({
data,
columns,
storageKey: "payments",
})
return <DataTable {...tableState} />
}Composable Helpers
The data table exports additional components for building advanced table UIs:
DataTableColumnHeader
A reusable column header with a dropdown for sorting and hiding columns.
import { DataTableColumnHeader } from "@/components/ui/data-table"
{
accessorKey: "email",
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Email" />
),
}DataTablePagination
A standalone pagination component. The DataTable includes this by default, but you can also use it separately when building custom table layouts.
import { DataTablePagination } from "@/components/ui/data-table"
<DataTablePagination table={table} />DataTableViewOptions
A column visibility toggle dropdown. Use this in a toolbar above the table.
import { DataTableViewOptions } from "@/components/ui/data-table"
<DataTableViewOptions table={table} />State Management Hooks
The Data Table requires external state for sorting, filtering, pagination, column visibility, column order, and row selection. Two hooks are provided that manage this state and return props compatible with DataTable:
useDataTable
A generic hook for managing Data Table state with any data source. It handles persisting sorting, column visibility, and column order to localStorage.
Installation
npx shadcn@latest add @uipath/use-data-tableUsage
The hook returns an object that can be spread directly into DataTable:
"use client"
import { DataTable } from "@/components/ui/data-table"
import { useDataTable } from "@/hooks/use-data-table"
import { columns } from "./columns"
export default function PaymentsPage({ data }: { data: Payment[] }) {
const tableState = useDataTable({
data,
columns,
storageKey: "payments",
defaultVisibleColumns: ["status", "email", "amount"],
})
return <DataTable {...tableState} />
}Options
| Option | Type | Description |
|---|---|---|
data | TData[] | The data array to display |
columns | ColumnDef<TData>[] | TanStack Table column definitions |
storageKey | string | Key used to persist state in localStorage |
isLoading | boolean | Optional loading state (default: false) |
defaultColumnOrder | string[] | Initial column order (defaults to column definition order) |
defaultVisibleColumns | string[] | Initially visible columns (defaults to all) |
useEntityDataTable
A specialized hook for entity-based tables that integrates with VSS (Virtual Solution Storage). It extends useDataTable by automatically generating column definitions from entity metadata and fetching data via useLiveQuery.
Installation
npx shadcn@latest add @uipath/use-entity-data-tableUsage
"use client"
import { DataTable } from "@/components/ui/data-table"
import { useEntityDataTable } from "@/hooks/use-entity-data-table"
export default function EntityPage({ entity }: { entity: VssEntity }) {
const tableState = useEntityDataTable({
entity,
storageKey: "my-entity",
initialVisibleColumnCount: 6,
systemFields: ["Id"],
})
return <DataTable {...tableState} />
}Options
| Option | Type | Description |
|---|---|---|
entity | VssEntity | The VSS entity definition (provides fields and metadata) |
storageKey | string | Key used to persist state (defaults to entity-{name}) |
initialVisibleColumnCount | number | Number of columns visible by default (default: 8) |
systemFields | string[] | Fields to exclude from the table (default: ["Id"]) |
columnOrder | string[] | Explicit column order override |
extraColumns | ExtraColumn[] | Additional columns injected at "start" or "end" |
columnOverrides | Record<string, (def) => def> | Per-column definition overrides |
Persisted State
Both hooks automatically persist the following state to localStorage:
- Sorting — stored under
entity-table-sorting-{storageKey} - Column visibility — stored under
entity-table-columns-{storageKey} - Column order — stored under
entity-table-column-order-{storageKey} - Global filter (entity hook only) — stored under
entity-table-global-filter-{storageKey}
Row Selection
Add a selection column using the Checkbox component:
import { Checkbox } from "@/components/ui/checkbox"
const columns: ColumnDef<Payment>[] = [
{
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"
/>
),
enableSorting: false,
enableHiding: false,
},
// ... other columns
]