Cheatsheet

Cheatsheet - TanStack Virtual

Decision rules

  • The list has a fixed viewport and ordinary item scrolling -> use useVirtualizer with count, getScrollElement, and estimateSize.
  • The browser window scrolls the page -> use useWindowVirtualizer and account for scrollMargin.
  • Every item has a known stable size -> return that size and position with height or width; skip DOM measurement.
  • Item size varies but content is already known -> return data[index] from estimateSize.
  • Item size changes after render -> use measureElement and data-index; use resizeItem when the final size comes from outside the DOM.
  • A row is text-only and wrapping determines height -> use Pretext; cache prepare, rerun layout on width changes, and call measure() after font changes.
  • A chat feed appends at the end or prepends history -> use anchorTo: 'end', stable IDs, followOnAppend, and an end threshold.
  • A list has sticky group headers -> customize rangeExtractor but retain defaultRangeExtractor(range).
  • A list needs more pages -> add one loader row to count and trigger fetching when the last virtual item reaches it.
  • A large 2D surface needs both axes virtualized -> create row and column virtualizers; use lanes for masonry-like distribution instead.
  • A header occupies the virtual content start -> use paddingStart; if scroll-to-index must avoid it, also use scrollPaddingStart.
  • Scrolling shows blank gaps -> increase overscan; if rendering becomes expensive, reduce it and optimize the row.
  • React 19 emits flushSync scrolling warnings -> set useFlushSync: false; this also permits more batching.
  • High-frequency scroll updates need fewer React renders -> consider directDomUpdates or an onChange DOM update path after measuring the trade-off.

Common defaults from the examples

SituationExample setting
Ordinary fixed/variable listoverscan: 5
End-anchored chatoverscan: 6, scrollEndThreshold: 80
TableestimateSize: () => 34, overscan: 20
Fixed rowsestimateSize: () => 35
Fixed columnsestimateSize: () => 100

Geometry checklist

  1. The scroll element has a real height or width and overflow: auto.
  2. The inner element uses getTotalSize() on the virtualized axis.
  3. Each virtual item uses key, index, start, and size.
  4. Absolute positioning and the correct translateY or translateX are applied.
  5. Dynamic items have one, and only one, sizing owner.