| name | with-tanstack-virtual |
| description | Virtualize final React Table row or column models with TanStack Virtual. Load for useVirtualizer counts, scroll elements, stable keys, data-index measurement, dynamic heights, sticky headers/columns, grid/flex geometry, or infinite fetching; Virtual is renderer composition, not a Table feature.
|
| metadata | {"type":"composition","library":"@tanstack/react-table","library_version":"9.2.4","framework":"react"} |
| requires | ["@tanstack/table-core#core","getting-started","table-state"] |
| sources | ["TanStack/table:docs/framework/react/guide/virtualization.md","TanStack/table:examples/react/virtualized-rows","TanStack/table:examples/react/virtualized-columns","TanStack/table:examples/react/virtualized-infinite-scrolling"] |
This skill builds on @tanstack/table-core#core, getting-started, and table-state. Build the Table model first, then virtualize its final rendered rows or visible columns.
Setup
import { useRef } from 'react'
import { useVirtualizer } from '@tanstack/react-virtual'
function VirtualBody({ table }: { table: any }) {
const scrollRef = useRef<HTMLDivElement>(null)
const rows = table.getRowModel().rows
const virtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => 36,
getItemKey: (index) => rows[index].id,
overscan: 5,
})
return (
<div ref={scrollRef} style={{ height: 400, overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
{virtualizer.getVirtualItems().map((item) => (
<div
key={rows[item.index].id}
data-index={item.index}
ref={virtualizer.measureElement}
style={{
position: 'absolute',
transform: `translateY(${item.start}px)`,
width: '100%',
}}
>
{rows[item.index].getAllCells().map((cell: any) => (
<span
key={cell.id}
style={{
display: 'inline-block',
width: cell.column.getSize(),
}}
>
<table.FlexRender cell={cell} />
</span>
))}
</>
))}
)
}
Core Patterns
Keep the virtualizer near its render loop
const rows = table.getRowModel().rows
const rowVirtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => container.current,
estimateSize: () => 36,
})
This limits unrelated parent updates and keeps count, measurement, and rendered items together.
Use Table sizes in renderer CSS
<td style={{ width: cell.column.getSize() }}>
<table.FlexRender cell={cell} />
</td>
Table calculates size state; the renderer must apply it.
Common Mistakes
HIGH Registering Virtual as a feature
Wrong:
const features = tableFeatures({ rowVirtualizer: useVirtualizer(options) })
Correct:
const rows = table.getRowModel().rows
const virtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => 36,
})
Virtual controls rendering geometry and is not a Table feature or row model.
Source: docs/framework/react/guide/virtualization.md
HIGH Virtualizing raw input data
Wrong:
const virtualizer = useVirtualizer({
count: data.length,
getScrollElement,
estimateSize,
})
Correct:
const rows = table.getRowModel().rows
const virtualizer = useVirtualizer({
count: rows.length,
getScrollElement,
estimateSize,
})
Raw data ignores filtering, sorting, expansion, grouping, and pagination already applied by Table.
Source: examples/react/virtualized-rows
HIGH Measuring against incomplete identity
Wrong:
<tr ref={virtualizer.measureElement}>{row.id}</tr>
Correct:
<tr key={row.id} data-index={item.index} ref={virtualizer.measureElement}>
{row.id}
</tr>
Dynamic measurement needs the virtual index, and stable row identity prevents measurements moving to the wrong row.
Source: examples/react/virtualized-rows
HIGH Omitting positioning geometry
Wrong:
<tbody>{virtualizer.getVirtualItems().map(renderRow)}</tbody>
Correct:
<tbody
style={{
display: 'grid',
height: virtualizer.getTotalSize(),
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map(renderRow)}
</tbody>
Virtual only computes positions; the renderer must provide total spacer size and position items using each virtual start.
Source: examples/react/virtualized-rows
API Discovery
Inspect node_modules/@tanstack/react-table/dist/index.d.ts for Table render APIs and installed node_modules/@tanstack/react-virtual/dist/ for the exact virtualizer options. Copy layout contracts from the maintained example matching rows, columns, or infinite loading.