Shadcn React Table

Search documentation

Search the docs

Virtualization

Virtualization renders only the cells currently in view, keeping large tables fast. The data table supports both row and column virtualization.

Row virtualization

Set enableRowVirtualization: true to render only the visible rows. This is recommended once you have more than roughly 100 rows.

Virtualized (1,000 rows)Row virtualization for large datasets.
GitHub
ID
$89,671,500

With row virtualization on, the table surface becomes the scroll container, so give it a bounded height via slotProps.surface (it defaults to a viewport-based height).

tsx
import { DataTable, useDataTable } from "@/components/ui/data-table"

const table = useDataTable({
  data,
  columns,
  getRowId: (row) => row.id,
  enableRowVirtualization: true,
  slotProps: { surface: { className: "max-h-[600px]" } },
  estimateRowHeight: 52,
  virtualOverscan: 8,
})

return <DataTable table={table} />

Tune the behavior with estimateRowHeight (default 52) and virtualOverscan (default 8, the number of extra rows rendered above and below the viewport).

Advanced virtualizer control

For finer control, both virtualizers expose the underlying @tanstack/react-virtual API.

Pass rowVirtualizerOptions / columnVirtualizerOptions to merge extra options into the useVirtualizer call. They override the built-in count, estimateSize, overscan, and measureElement, and accept either an object or a ({ table }) => options function:

tsx
const table = useDataTable({
  data,
  columns,
  enableRowVirtualization: true,
  rowVirtualizerOptions: { overscan: 12, gap: 4 },
})

To drive the virtualizer imperatively (for example, to scroll to a row), pass a ref via rowVirtualizerInstanceRef / columnVirtualizerInstanceRef:

tsx
import { useRef } from "react"
import type { DataTableRowVirtualizer } from "@/components/ui/data-table"

const rowVirtualizerRef = useRef<DataTableRowVirtualizer>(null)

const table = useDataTable({
  data,
  columns,
  enableRowVirtualization: true,
  rowVirtualizerInstanceRef: rowVirtualizerRef,
})

// later, e.g. in an effect or event handler:
rowVirtualizerRef.current?.scrollToIndex(100)

Dragging rows

Rows can be dragged with virtualization on (enableRowOrdering, enableRowDragging): the table scrolls as you drag toward its edge, and the dragged row stays rendered. See Row ordering.

Column virtualization

For very wide tables, set enableColumnVirtualization: true to virtualize columns. This applies fixed column widths. Column pinning (pinned columns stay in place while you scroll sideways), column ordering and grouped headers all work with it.

Column virtualizationHorizontal virtualization for very wide tables (34 columns × 300 rows).
GitHub
tsx
import { DataTable, useDataTable } from "@/components/ui/data-table"

const table = useDataTable({
  data,
  columns,
  getRowId: (row) => row.id,
  enableColumnVirtualization: true,
  enablePagination: false,
})

return <DataTable table={table} />

Pair with no pagination

Column virtualization is usually paired with enablePagination: false so all rows scroll within one virtualized surface.

Relevant options

PropTypeDefaultDescription
enableRowVirtualization?booleanfalseVirtualize body rows for large datasets (recommended past ~100 rows). The table surface becomes the scroll container — give it a bounded height via `className`/`style` (defaults to `max-h-[600px]`). Rows can still be dragged: the dragged row stays rendered while the drag scrolls.
enableColumnVirtualization?booleanfalseVirtualize columns for very wide tables. Applies fixed column widths; works with column pinning (pinned columns stay rendered), column ordering and grouped headers.
estimateRowHeight?number52Estimated row height (px) for the virtualizer. Default 52.
virtualOverscan?number8Extra rows rendered above/below the viewport. Default 8.
rowVirtualizerOptions?RowVirtualizerOptions<TData>—Partial `@tanstack/react-virtual` options merged into the row virtualizer (overrides the built-in `count`/`estimateSize`/`overscan`/`measureElement`). A `rangeExtractor` picks the rendered rows; a row being dragged is added to its result. Accepts an object or a `({ table }) => options` function.
columnVirtualizerOptions?ColumnVirtualizerOptions<TData>—Partial `@tanstack/react-virtual` options merged into the column virtualizer. Accepts an object or a `({ table }) => options` function.
rowVirtualizerInstanceRef?React.RefObject<DataTableRowVirtualizer | null>—Ref populated with the row `Virtualizer` instance for imperative control (e.g. `scrollToIndex`). Only set when `enableRowVirtualization`.
columnVirtualizerInstanceRef?React.RefObject<DataTableColumnVirtualizer | null>—Ref populated with the column `Virtualizer` instance. Only set when `enableColumnVirtualization`.