Skip to content

Core Components

Essential building blocks of the data table including DataTableRoot, DataTable, and structure components.

Core components are the essential building blocks of the data table. They handle table initialization, context management, and basic structure.

The DataTableRoot component provides the table context to all child components. You should always wrap your table in a DataTableRoot. It initializes the TanStack Table instance and manages table state.

import { DataTableRoot } from "@/components/niko-table/core/data-table-root"
export function MyTable({ data }: { data: User[] }) {
return (
<DataTableRoot data={data} columns={columns}>
{/* child components */}
</DataTableRoot>
)
}
NameTypeDescription
childrenReact.ReactNodeChild components (required).
dataTData[]The data array to display in the table.
columnsDataTableColumnDef<TData>[]Column definitions array.
tableTable<TData>Pre-configured TanStack Table instance (optional).
configDataTableConfigConfiguration object for feature toggles.
isLoadingbooleanLoading state for the table.
getRowId(row: TData, index: number) => stringCustom function to get row IDs.
classNamestringAdditional CSS classes.
statePartial<TableState>Controlled table state (pagination, sorting, etc).
NameTypeDescription
onGlobalFilterChange(value: GlobalFilter) => voidCalled when global filter changes.
onPaginationChange(updater: Updater<PaginationState>) => voidCalled when pagination changes.
onSortingChange(updater: Updater<SortingState>) => voidCalled when sorting changes.
onColumnFiltersChange(updater: Updater<ColumnFiltersState>) => voidCalled when column filters change.
onColumnVisibilityChange(updater: Updater<VisibilityState>) => voidCalled when column visibility changes.
onRowSelectionChange(updater: Updater<RowSelectionState>) => voidCalled when row selection changes.
onExpandedChange(updater: Updater<ExpandedState>) => voidCalled when expanded state changes.
onColumnPinningChange(updater: Updater<ColumnPinningState>) => voidCalled when column pinning changes.
onColumnOrderChange(updater: Updater<ColumnOrderState>) => voidCalled when column order changes.
onRowSelection(selectedRows: TData[]) => voidCalled with selected row data.

The config prop accepts a DataTableConfig object with the following properties:

NameTypeDefaultDescription
enablePaginationbooleantrueEnable pagination.
enableFiltersbooleantrueEnable filtering.
enableSortingbooleantrueEnable sorting.
enableRowSelectionbooleanfalseEnable row selection.
enableMultiSortbooleantrueEnable multi-column sorting.
enableGroupingbooleanfalseEnable column grouping.
enableExpandingbooleanfalseEnable row expansion.
manualSortingbooleanfalseEnable server-side sorting.
manualPaginationbooleanfalseEnable server-side pagination.
manualFilteringbooleanfalseEnable server-side filtering.
pageCountnumber-Total pages (required for server-side pagination).
initialPageSizenumber10Initial page size.
initialPageIndexnumber0Initial page index.
autoResetPageIndexboolean-Auto-reset page on filter/sort change. Defaults to false when manualPagination: true, otherwise true.
autoResetExpandedbooleantrueAuto-reset expanded rows on filter/sort change.

Low-level context provider used internally by DataTableRoot. Use this directly when you need to provide a pre-configured TanStack Table instance to the context (e.g., when using useReactTable yourself).

import { DataTableProvider } from "@/components/niko-table/core/data-table-context"
import { useReactTable, getCoreRowModel } from "@tanstack/react-table"
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
<DataTableProvider table={table} columns={columns} isLoading={false}>
{/* child components can use useDataTable() */}
</DataTableProvider>
NameTypeDescription
tableDataTableInstance<TData>TanStack Table instance (required).
columnsDataTableColumnDef<TData>[]Column definitions (optional).
isLoadingbooleanLoading state (optional).
childrenReact.ReactNodeChild components.

The raw React context object. Useful for advanced scenarios where you need direct access to the context (e.g., conditional rendering based on context availability).

import { DataTableContext } from "@/components/niko-table/core/data-table-context"
import { useContext } from "react"
const context = useContext(DataTableContext)

The main table container component that wraps the table structure and provides scrolling behavior.

import { DataTable } from "@/components/niko-table/core/data-table"
<DataTable className="rounded-md border" height={600}>
<DataTableHeader />
<DataTableBody />
</DataTable>
NameTypeDefaultDescription
classNamestring-Additional CSS classes. Height utilities (e.g., h-[600px]) are automatically extracted and applied.
childrenReact.ReactNode-Child components (Header, Body).
heightnumber | string-Sets the height of the table container. Enables vertical scrolling and scroll event callbacks.
maxHeightnumber | string-Sets the maximum height of the table container. Defaults to the height value if not specified.

Renders the table header with sortable columns.

import { DataTableHeader } from "@/components/niko-table/core/data-table-structure"
<DataTableHeader sticky={true} />
NameTypeDefaultDescription
classNamestring-Additional CSS classes.
stickybooleantrueMakes the header sticky at the top when scrolling.

Renders the table body with rows. Supports scroll events and row expansion.

import {
DataTableBody,
DataTableSkeleton,
DataTableEmptyBody,
} from "@/components/niko-table/core/data-table-structure"
<DataTableBody
onScroll={e => console.log(`Scrolled ${e.percentage}%`)}
onScrolledBottom={() => loadMore()}
>
<DataTableSkeleton />
<DataTableEmptyBody />
</DataTableBody>
NameTypeDefaultDescription
classNamestring-Additional CSS classes.
childrenReact.ReactNode-Child components (Skeleton, EmptyBody).
onScroll(event: ScrollEvent) => void-Scroll event handler.
onScrolledTop() => void-Called when scrolled to top.
onScrolledBottom() => void-Called when scrolled to bottom.
scrollThresholdnumber50Threshold for scroll events.
onRowClick(row: TData) => void-Called when a row is clicked.

The ScrollEvent object passed to onScroll contains:

PropertyTypeDescription
scrollTopnumberCurrent scroll position from top.
scrollHeightnumberTotal scrollable height.
clientHeightnumberVisible height of the container.
isTopbooleanWhether scrolled to the top.
isBottombooleanWhether scrolled to the bottom.
percentagenumberScroll percentage (0-100).

Shows a loading skeleton when isLoading is true. Automatically matches the table structure.

<DataTableBody>
<DataTableSkeleton rows={5} />
</DataTableBody>
NameTypeDefaultDescription
rowsnumber5Number of skeleton rows to display.
colSpannumber-Number of columns (auto-detected if not provided).
classNamestring-Additional CSS classes.
cellClassNamestring-CSS classes for skeleton cells.
skeletonClassNamestring-CSS classes for skeleton elements.
childrenReact.ReactNode-Custom skeleton content (replaces rows).

Shows an empty state when there’s no data. Uses composition pattern with DataTableEmpty* components.

<DataTableBody>
<DataTableEmptyBody>
<DataTableEmptyIcon>
<PackageOpen className="size-12" />
</DataTableEmptyIcon>
<DataTableEmptyMessage>
<DataTableEmptyTitle>No products found</DataTableEmptyTitle>
<DataTableEmptyDescription>
Get started by adding your first product
</DataTableEmptyDescription>
</DataTableEmptyMessage>
<DataTableEmptyFilteredMessage>
No results match your filters
</DataTableEmptyFilteredMessage>
<DataTableEmptyActions>
<Button onClick={handleAdd}>Add Product</Button>
</DataTableEmptyActions>
</DataTableEmptyBody>
</DataTableBody>
NameTypeDefaultDescription
childrenReact.ReactNode-Empty state composition components.
colSpannumber-Number of columns (auto-detected if not provided).
classNamestring-Additional CSS classes.

Shows a loading indicator when isLoading is true.

<DataTableBody>
<DataTableLoading>
<Spinner />
</DataTableLoading>
</DataTableBody>
NameTypeDefaultDescription
childrenReact.ReactNode-Custom loading content.
colSpannumber-Number of columns (auto-detected if not provided).
classNamestring-Additional CSS classes.

Error boundary component that catches errors in the data table component tree and displays a fallback UI.

import { DataTableErrorBoundary } from "@/components/niko-table/core/data-table-error-boundary"
<DataTableErrorBoundary
onError={(error, errorInfo) => {
console.error("Table error:", error)
trackError(error)
}}
>
<DataTableRoot data={data} columns={columns}>
{/* table components */}
</DataTableRoot>
</DataTableErrorBoundary>
NameTypeDefaultDescription
childrenReact.ReactNode-The content to render when there’s no error.
fallbackReact.ReactNode-Custom fallback UI to show when an error occurs.
onError(error: Error, errorInfo: React.ErrorInfo) => void-Callback fired when an error is caught.
showResetButtonbooleantrueWhether to show a reset button.
resetButtonTextstring"Try Again"Custom reset button text.

For large datasets (1000+ rows), use the virtualized variants for optimal performance.

Virtualized table header component.

import {
DataTableVirtualizedHeader,
DataTableVirtualizedBody,
} from "@/components/niko-table/core/data-table-virtualized-structure"
<DataTable>
<DataTableVirtualizedHeader />
<DataTableVirtualizedBody estimateSize={34} overscan={20}>
{/* rows */}
</DataTableVirtualizedBody>
</DataTable>
NameTypeDefaultDescription
classNamestring-Additional CSS classes.
stickybooleantrueMakes the header sticky at the top when scrolling.

Virtualized table body for rendering thousands of rows efficiently.

NameTypeDefaultDescription
childrenReact.ReactNode-Child components (VirtualizedSkeleton, VirtualizedEmptyBody).
estimateSizenumber34Estimated row height in pixels.
overscannumber20Number of items to render outside visible area.
classNamestring-Additional CSS classes.
onScroll(event: ScrollEvent) => void-Scroll event handler.
onScrolledTop() => void-Called when scrolled to top.
onScrolledBottom() => void-Called when scrolled to bottom.
scrollThresholdnumber50Threshold for scroll events.
onRowClick(row: TData, event: React.MouseEvent) => void-Called when a row is clicked.

Empty state component for virtualized tables.

import {
DataTableVirtualizedBody,
DataTableVirtualizedEmptyBody,
} from "@/components/niko-table/core/data-table-virtualized-structure"
import {
DataTableEmptyIcon,
DataTableEmptyMessage,
DataTableEmptyTitle,
DataTableEmptyDescription,
} from "@/components/niko-table/components/data-table-empty-state"
import { PackageOpen } from "lucide-react"
<DataTableVirtualizedBody estimateSize={34}>
<DataTableVirtualizedEmptyBody>
<DataTableEmptyIcon>
<PackageOpen className="size-12" />
</DataTableEmptyIcon>
<DataTableEmptyMessage>
<DataTableEmptyTitle>No data found</DataTableEmptyTitle>
<DataTableEmptyDescription>
Get started by adding your first item
</DataTableEmptyDescription>
</DataTableEmptyMessage>
</DataTableVirtualizedEmptyBody>
</DataTableVirtualizedBody>
NameTypeDefaultDescription
childrenReact.ReactNode-Empty state composition components.
colSpannumber-Number of columns (auto-detected if not provided).
classNamestring-Additional CSS classes.

Loading skeleton for virtualized tables.

import {
DataTableVirtualizedBody,
DataTableVirtualizedSkeleton,
} from "@/components/niko-table/core/data-table-virtualized-structure"
<DataTableVirtualizedBody estimateSize={34}>
<DataTableVirtualizedSkeleton rows={10} estimateSize={34} />
</DataTableVirtualizedBody>
NameTypeDefaultDescription
rowsnumber5Number of skeleton rows to display.
estimateSizenumber34Estimated row height (should match VirtualizedBody).
classNamestring-Additional CSS classes.
cellClassNamestring-CSS classes for skeleton cells.
skeletonClassNamestring-CSS classes for skeleton elements.
childrenReact.ReactNode-Custom skeleton content.

Loading indicator for virtualized tables.

import {
DataTableVirtualizedBody,
DataTableVirtualizedLoading,
} from "@/components/niko-table/core/data-table-virtualized-structure"
import { Loader2 } from "lucide-react"
<DataTableVirtualizedBody estimateSize={34}>
<DataTableVirtualizedLoading>
<div className="flex items-center justify-center p-8">
<Loader2 className="size-6 animate-spin" />
<span className="ml-2">Loading...</span>
</div>
</DataTableVirtualizedLoading>
</DataTableVirtualizedBody>
NameTypeDefaultDescription
childrenReact.ReactNode-Custom loading content.
colSpannumber-Number of columns (auto-detected if not provided).
classNamestring-Additional CSS classes.

Choose the right DnD components based on your use case:

Use CaseComponents
Row reorder (standard)DataTableDndBody
Column reorder (standard)DataTableDndHeader + DataTableDndColumnBody
Row reorder (virtualized)DataTableVirtualizedDndBody
Column reorder (virtualized)DataTableVirtualizedDndHeader + DataTableVirtualizedDndColumnBody

For standard (non-virtualized) tables with drag-and-drop, use these components from data-table-dnd-structure.tsx. They are drop-in replacements for DataTableHeader / DataTableBody when using row or column DnD.

DnD-aware table body that renders rows as draggable items. Drop-in replacement for DataTableBody when using row drag-and-drop. Must be wrapped in a DataTableRowDndProvider.

import { DataTableDndBody } from "@/components/niko-table/core/data-table-dnd-structure"
import { DataTableRowDndProvider } from "@/components/niko-table/components/data-table-row-dnd"
<DataTableRowDndProvider data={data} onReorder={setData}>
<DataTable>
<DataTableHeader />
<DataTableDndBody />
</DataTable>
</DataTableRowDndProvider>
NameTypeDefaultDescription
childrenReact.ReactNode-Child components.
classNamestring-Additional CSS classes.
onRowClick(row: TData) => void-Called when a row is clicked.

DnD-aware table header that renders column headers as draggable items. Drop-in replacement for DataTableHeader when using column drag-and-drop. Must be wrapped in a DataTableColumnDndProvider.

import { DataTableDndHeader, DataTableDndColumnBody } from "@/components/niko-table/core/data-table-dnd-structure"
import { DataTableColumnDndProvider } from "@/components/niko-table/components/data-table-column-dnd"
<DataTableColumnDndProvider columnOrder={columnOrder} onColumnOrderChange={setColumnOrder}>
<DataTable>
<DataTableDndHeader />
<DataTableDndColumnBody />
</DataTable>
</DataTableColumnDndProvider>
NameTypeDefaultDescription
classNamestring-Additional CSS classes.
stickybooleantrueMakes the header sticky at the top when scrolling.

DnD-aware table body for column drag-and-drop. Each cell follows its column’s drag position using useSortable. Must be wrapped in a DataTableColumnDndProvider.

NameTypeDefaultDescription
childrenReact.ReactNode-Child components.
classNamestring-Additional CSS classes.
onRowClick(row: TData) => void-Called when a row is clicked.

For combining virtualization with drag-and-drop, use these specialized components from data-table-virtualized-dnd-structure.tsx.

Virtualized DnD-aware table body for row drag-and-drop. Combines @tanstack/react-virtual for windowing with @dnd-kit/sortable for drag interactions. Must be wrapped in a DataTableRowDndProvider.

import {
DataTableVirtualizedHeader,
DataTableVirtualizedDndBody,
DataTableVirtualizedEmptyBody,
} from "@/components/niko-table/core/data-table-virtualized-dnd-structure"
import { DataTableRowDndProvider } from "@/components/niko-table/components/data-table-row-dnd"
<DataTableRowDndProvider data={data} onReorder={setData}>
<DataTable height={500}>
<DataTableVirtualizedHeader />
<DataTableVirtualizedDndBody estimateSize={40} overscan={10}>
<DataTableVirtualizedEmptyBody />
</DataTableVirtualizedDndBody>
</DataTable>
</DataTableRowDndProvider>
NameTypeDefaultDescription
childrenReact.ReactNode-Child components (e.g. DataTableVirtualizedEmptyBody).
estimateSizenumber34Estimated row height in pixels.
overscannumber20Number of items to render outside visible area.
classNamestring-Additional CSS classes.
onScroll(event: ScrollEvent) => void-Scroll event handler.
onScrolledTop() => void-Called when scrolled to top.
onScrolledBottom() => void-Called when scrolled to bottom.
scrollThresholdnumber50Pixel threshold for top/bottom scroll events.
onRowClick(row: TData, event: React.MouseEvent) => void-Called when a row is clicked.

Virtualized DnD-aware table header for column drag-and-drop. Must be wrapped in a DataTableColumnDndProvider.

import {
DataTableVirtualizedDndHeader,
DataTableVirtualizedDndColumnBody,
} from "@/components/niko-table/core/data-table-virtualized-dnd-structure"
import { DataTableColumnDndProvider } from "@/components/niko-table/components/data-table-column-dnd"
<DataTableColumnDndProvider columnOrder={columnOrder} onColumnOrderChange={setColumnOrder}>
<DataTable height={500}>
<DataTableVirtualizedDndHeader />
<DataTableVirtualizedDndColumnBody estimateSize={40} />
</DataTable>
</DataTableColumnDndProvider>
NameTypeDefaultDescription
classNamestring-Additional CSS classes.
stickybooleantrueMakes the header sticky at the top when scrolling.

Virtualized DnD-aware table body for column drag-and-drop. Each cell follows column drag position using useSortable. Must be wrapped in a DataTableColumnDndProvider.

NameTypeDefaultDescription
childrenReact.ReactNode-Child components (e.g. DataTableVirtualizedEmptyBody).
estimateSizenumber34Estimated row height in pixels.
overscannumber20Number of items to render outside visible area.
classNamestring-Additional CSS classes.
onScroll(event: ScrollEvent) => void-Scroll event handler.
onScrolledTop() => void-Called when scrolled to top.
onScrolledBottom() => void-Called when scrolled to bottom.
scrollThresholdnumber50Pixel threshold for top/bottom scroll events.
onRowClick(row: TData, event: React.MouseEvent) => void-Called when a row is clicked.