Headless UI for virtualizing scrollable elements in React
npx @tessl/cli install tessl/npm-tanstack--react-virtual@3.13.0TanStack React Virtual is a headless UI library for virtualizing scrollable elements in React. It enables efficient rendering of large lists and grids by only rendering visible items in the DOM, providing smooth scrolling performance and minimal memory footprint for data-heavy applications.
npm install @tanstack/react-virtualimport {
useVirtualizer,
useWindowVirtualizer,
Virtualizer,
// Types
VirtualItem,
VirtualizerOptions,
Rect,
Range,
ScrollToOptions,
ScrollAlignment,
ScrollBehavior,
Key,
// Utility functions
defaultKeyExtractor,
defaultRangeExtractor,
observeElementRect,
observeElementOffset,
observeWindowRect,
observeWindowOffset,
elementScroll,
windowScroll,
measureElement,
// Advanced utilities
memo,
notUndefined,
approxEqual,
debounce,
PartialKeys,
NoInfer
} from "@tanstack/react-virtual";For CommonJS:
const {
useVirtualizer,
useWindowVirtualizer,
Virtualizer,
VirtualItem,
defaultKeyExtractor,
defaultRangeExtractor,
// ... other exports
} = require("@tanstack/react-virtual");import React from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
function VirtualList() {
const parentRef = React.useRef<HTMLDivElement>(null);
const virtualizer = useVirtualizer({
count: 10000,
getScrollElement: () => parentRef.current,
estimateSize: () => 35,
});
return (
<div
ref={parentRef}
style={{
height: `400px`,
overflow: 'auto',
}}
>
<div
style={{
height: `${virtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{virtualizer.getVirtualItems().map((virtualItem) => (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
data-index={virtualItem.index}
>
Row {virtualItem.index}
</div>
))}
</div>
</div>
);
}TanStack React Virtual is built around several key components:
useVirtualizer and useWindowVirtualizer provide React-specific virtualization functionalityVirtualizer class handles all virtualization logic including measurement, scrolling, and range calculationReact-specific hooks that provide virtualized scrolling for elements and windows with automatic state management and optimal re-rendering.
function useVirtualizer<TScrollElement extends Element, TItemElement extends Element>(
options: PartialKeys<VirtualizerOptions<TScrollElement, TItemElement>, 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'>
): Virtualizer<TScrollElement, TItemElement>;
function useWindowVirtualizer<TItemElement extends Element>(
options: PartialKeys<VirtualizerOptions<Window, TItemElement>, 'getScrollElement' | 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'>
): Virtualizer<Window, TItemElement>;The core virtualization engine class that manages all aspects of virtual scrolling including item measurement, range calculation, and scroll positioning.
class Virtualizer<TScrollElement extends Element | Window, TItemElement extends Element> {
constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>);
// Core methods
getVirtualItems(): Array<VirtualItem>;
scrollToIndex(index: number, options?: ScrollToIndexOptions): void;
scrollToOffset(toOffset: number, options?: ScrollToOffsetOptions): void;
getTotalSize(): number;
measureElement(node: TItemElement | null | undefined): void;
}
interface VirtualizerOptions<TScrollElement extends Element | Window, TItemElement extends Element> {
count: number;
getScrollElement: () => TScrollElement | null;
estimateSize: (index: number) => number;
scrollToFn: (offset: number, options: ScrollOptions, instance: Virtualizer<TScrollElement, TItemElement>) => void;
observeElementRect: (instance: Virtualizer<TScrollElement, TItemElement>, cb: (rect: Rect) => void) => void | (() => void);
observeElementOffset: (instance: Virtualizer<TScrollElement, TItemElement>, cb: (offset: number, isScrolling: boolean) => void) => void | (() => void);
// ... additional optional properties
}Core type definitions, interfaces, and utility functions used throughout the virtualization system.
interface VirtualItem {
key: Key;
index: number;
start: number;
end: number;
size: number;
lane: number;
}
interface Rect {
width: number;
height: number;
}
interface Range {
startIndex: number;
endIndex: number;
overscan: number;
count: number;
}For lists with consistent item heights:
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50, // Fixed height
});For lists with varying item heights:
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: (index) => items[index]?.estimatedHeight ?? 50,
measureElement: (element, entry, instance) => {
// Custom measurement logic if needed
return element.offsetHeight;
},
});For grid virtualization with multiple columns:
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 200,
lanes: 3, // 3-column grid
gap: 16, // Space between items
});For virtualizing content in the main window:
const virtualizer = useWindowVirtualizer({
count: items.length,
estimateSize: () => 100,
overscan: 5,
});