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.
65
80%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./packages/react-table/skills/with-tanstack-virtual/SKILL.mdThis 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.
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>
))}
</div>
))}
</div>
</div>
)
}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.
<td style={{ width: cell.column.getSize() }}>
<table.FlexRender cell={cell} />
</td>Table calculates size state; the renderer must apply it.
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
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
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
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
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.
9e523bc
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.