Command Palette

Search for a command to run...

Data Table

A full-featured data table built on TanStack Table: sticky column pinning, row virtualization for large datasets, dnd-kit drag-to-reorder rows, a paginated footer, a filter toolbar with text / number / range (slider) / date / faceted (select) filters driven by per-column meta, a column-visibility view menu, sortable column headers, and a loading skeleton. Bring your own TanStack table instance; the pieces are composable.

A full-featured data table built on TanStack Table. You own the table instance (columns, models, state); ikui gives you the composable UI around it: a scroll container with sticky column pinning, opt-in row virtualization for large datasets, dnd-kit drag-to-reorder rows, a paginated footer, and a filter toolbar driven by per-column meta.

The toolbar reads each column's meta.variant and renders the matching control — text, number, range (a slider popover), date / dateRange (a calendar popover), and select / multiSelect (a faceted command popover) — alongside a column-visibility view menu. Sortable headers, a loading skeleton, and a row drag handle ship as separate pieces you compose as needed.

Installation

One-time setup: add the @ikui registry to your components.json.

components.json
{
  "registries": {
    "@ikui": "https://ik-ui.pages.dev/r/{name}.json"
  }
}

Then install the component:

pnpm dlx shadcn@latest add @ikui/data-table

Usage

Declare filters through columnDef.meta, then hand the table to DataTable with DataTableToolbar as its child.

import {
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { DataTable } from "@/components/data-table";
import { DataTableToolbar } from "@/components/data-table-toolbar";
import { DataTableColumnHeader } from "@/components/data-table-column-header";

const columns = [
  {
    accessorKey: "title",
    header: ({ column }) => (
      <DataTableColumnHeader column={column} title="Title" />
    ),
    meta: { label: "Title", variant: "text", placeholder: "Filter titles..." },
    enableColumnFilter: true,
    filterFn: "includesString",
  },
  {
    accessorKey: "status",
    header: "Status",
    meta: {
      label: "Status",
      variant: "select",
      options: [
        { label: "Todo", value: "todo" },
        { label: "Done", value: "done" },
      ],
    },
    enableColumnFilter: true,
    filterFn: "arrIncludesSome",
  },
];

function Example() {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  });

  return (
    <DataTable table={table}>
      <DataTableToolbar table={table} />
    </DataTable>
  );
}

Column meta

The toolbar and filters read these fields off columnDef.meta (types are added by data-table-utils.ts via module augmentation):

PropTypeDefault
label
string
-
placeholder
string
-
variant
"text" | "number" | "range" | "date" | "dateRange" | "select" | "multiSelect"
-
options
{ label; value; count?; icon? }[]
-
range
[number, number]
-
unit
string
-

Props

PropTypeDefault
table
Table<TData>
-
enableVirtualization
boolean
true
estimateRowSize
number
80
enableDragAndDrop
boolean
false
onDragEnd
(event: DragEndEvent) => void
-
getRowId
(row: TData) => number | string
-
showPagination
boolean
true
totalCount
number
-
actionBar
React.ReactNode
-
footer
React.ReactNode
-
emptyState
React.ReactNode
-