Headless UI for virtualizing scrollable elements in React
—
Core type definitions, interfaces, and utility functions used throughout the TanStack React Virtual virtualization system.
Essential interfaces that define the structure of virtual items and configuration objects.
/**
* Represents a virtualized item with position and size information
*/
export interface VirtualItem {
/** Unique key for the item (from getItemKey function) */
key: Key;
/** Zero-based index of the item in the data array */
index: number;
/** Start position of the item in pixels from the beginning of the scroll area */
start: number;
/** End position of the item in pixels from the beginning of the scroll area */
end: number;
/** Height (vertical) or width (horizontal) of the item in pixels */
size: number;
/** Lane number for grid layouts (0-based) */
lane: number;
}
/**
* Represents the dimensions of a rectangular area
*/
export interface Rect {
/** Width in pixels */
width: number;
/** Height in pixels */
height: number;
}
/**
* Defines a range of items with overscan information
*/
export interface Range {
/** Index of the first item in the range */
startIndex: number;
/** Index of the last item in the range */
endIndex: number;
/** Number of items to render outside the visible area */
overscan: number;
/** Total number of items in the dataset */
count: number;
}
/**
* Options for scrolling operations
*/
export interface ScrollToOptions {
/** How to align the target within the viewport */
align?: ScrollAlignment;
/** Scroll behavior (smooth or instant) */
behavior?: ScrollBehavior;
}Common type aliases used throughout the virtualization system.
/**
* Valid key types for identifying virtual items
*/
export type Key = number | string | bigint;
/**
* Direction of scroll movement
*/
export type ScrollDirection = 'forward' | 'backward';
/**
* How to align items when scrolling
*/
export type ScrollAlignment = 'start' | 'center' | 'end' | 'auto';
/**
* Browser scroll behavior
*/
export type ScrollBehavior = 'auto' | 'smooth';
/**
* Options for scrollToOffset method
*/
export type ScrollToOffsetOptions = ScrollToOptions;
/**
* Options for scrollToIndex method
*/
export type ScrollToIndexOptions = ScrollToOptions;Functions for observing element and window changes, used internally by the virtualization engine.
/**
* Observe changes to an element's dimensions using ResizeObserver
* @param instance - Virtualizer instance
* @param cb - Callback function to receive dimension updates
* @returns Cleanup function to stop observing
*/
export function observeElementRect<T extends Element>(
instance: Virtualizer<T, any>,
cb: (rect: Rect) => void
): void | (() => void);
/**
* Observe changes to window dimensions
* @param instance - Virtualizer instance for window
* @param cb - Callback function to receive dimension updates
* @returns Cleanup function to stop observing
*/
export function observeWindowRect(
instance: Virtualizer<Window, any>,
cb: (rect: Rect) => void
): void | (() => void);
/**
* Observe scroll offset changes for an element
* @param instance - Virtualizer instance
* @param cb - Callback function to receive offset and scrolling state
* @returns Cleanup function to stop observing
*/
export function observeElementOffset<T extends Element>(
instance: Virtualizer<T, any>,
cb: (offset: number, isScrolling: boolean) => void
): void | (() => void);
/**
* Observe scroll offset changes for the window
* @param instance - Virtualizer instance for window
* @param cb - Callback function to receive offset and scrolling state
* @returns Cleanup function to stop observing
*/
export function observeWindowOffset(
instance: Virtualizer<Window, any>,
cb: (offset: number, isScrolling: boolean) => void
): void | (() => void);Functions that handle scrolling for different element types.
/**
* Scroll function for DOM elements
* @param offset - Target scroll position in pixels
* @param options - Scroll options with adjustments and behavior
* @param instance - Virtualizer instance
*/
export function elementScroll<T extends Element>(
offset: number,
options: { adjustments?: number; behavior?: ScrollBehavior },
instance: Virtualizer<T, any>
): void;
/**
* Scroll function for the window
* @param offset - Target scroll position in pixels
* @param options - Scroll options with adjustments and behavior
* @param instance - Virtualizer instance
*/
export function windowScroll<T extends Window>(
offset: number,
options: { adjustments?: number; behavior?: ScrollBehavior },
instance: Virtualizer<T, any>
): void;Functions for measuring and calculating item sizes.
/**
* Measure the size of a DOM element
* @param element - Element to measure
* @param entry - ResizeObserver entry (optional)
* @param instance - Virtualizer instance
* @returns Size in pixels (height for vertical, width for horizontal)
*/
export function measureElement<TItemElement extends Element>(
element: TItemElement,
entry: ResizeObserverEntry | undefined,
instance: Virtualizer<any, TItemElement>
): number;Default implementation functions that can be customized.
/**
* Default key extraction function
* @param index - Item index
* @returns The index as the key
*/
export function defaultKeyExtractor(index: number): number;
/**
* Default range extraction function that includes overscan
* @param range - Range specification with overscan
* @returns Array of indexes to render
*/
export function defaultRangeExtractor(range: Range): Array<number>;Usage Examples:
import { defaultRangeExtractor, Range } from '@tanstack/react-virtual';
// Custom range extractor that limits overscan
function limitedRangeExtractor(range: Range): Array<number> {
const maxOverscan = 5;
const actualOverscan = Math.min(range.overscan, maxOverscan);
return defaultRangeExtractor({
...range,
overscan: actualOverscan
});
}
// Custom key extractor for complex data
function dataKeyExtractor(index: number): string {
return `item-${data[index]?.id ?? index}`;
}General utility functions used throughout the library.
/**
* Assert that a value is not undefined
* @param value - Value to check
* @param msg - Optional error message
* @returns The value if not undefined
* @throws Error if value is undefined
*/
export function notUndefined<T>(value: T | undefined, msg?: string): T;
/**
* Check if two numbers are approximately equal (within 1.01 pixels)
* @param a - First number
* @param b - Second number
* @returns True if approximately equal
*/
export function approxEqual(a: number, b: number): boolean;
/**
* Create a debounced version of a function
* @param targetWindow - Window object for setTimeout/clearTimeout
* @param fn - Function to debounce
* @param ms - Debounce delay in milliseconds
* @returns Debounced function
*/
export function debounce(
targetWindow: Window & typeof globalThis,
fn: Function,
ms: number
): Function;
/**
* Memoization utility with dependency tracking
* @param getDeps - Function that returns current dependencies
* @param fn - Function to memoize
* @param opts - Memoization options
* @returns Memoized function with updateDeps method
*/
export function memo<TDeps extends ReadonlyArray<any>, TResult>(
getDeps: () => [...TDeps],
fn: (...args: NoInfer<[...TDeps]>) => TResult,
opts: {
key: false | string;
debug?: () => boolean;
onChange?: (result: TResult) => void;
initialDeps?: TDeps;
}
): (() => TResult) & { updateDeps: (newDeps: [...TDeps]) => void };Advanced TypeScript utility types for better type safety.
/**
* Type that prevents TypeScript from inferring generic types
*/
export type NoInfer<A extends any> = [A][A extends any ? 0 : never];
/**
* Make specific keys of an interface optional while keeping others required
*/
export type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;Usage Examples:
import { PartialKeys, VirtualizerOptions } from '@tanstack/react-virtual';
// Example of PartialKeys usage - make some required options optional
type SimplifiedOptions<TScrollElement extends Element, TItemElement extends Element> =
PartialKeys<
VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>;
// This allows creating options objects without providing the complex observer functions
const options: SimplifiedOptions<HTMLDivElement, HTMLDivElement> = {
count: 1000,
getScrollElement: () => document.getElementById('container') as HTMLDivElement,
estimateSize: () => 50,
// observeElementRect, observeElementOffset, and scrollToFn are now optional
};import { useVirtualizer } from '@tanstack/react-virtual';
interface DataItem {
id: string;
name: string;
}
function CustomKeyList({ items }: { items: DataItem[] }) {
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
getItemKey: (index) => items[index]?.id ?? index,
});
return (
// Virtual list implementation
);
}import { useVirtualizer, defaultRangeExtractor, Range } from '@tanstack/react-virtual';
// Custom range extractor that adds extra items at the end
function extraEndRangeExtractor(range: Range): Array<number> {
const defaultIndexes = defaultRangeExtractor(range);
// Add 5 extra items at the end if we're near the bottom
if (range.endIndex >= range.count - 10) {
const extraItems = Math.min(5, range.count - 1 - range.endIndex);
for (let i = 1; i <= extraItems; i++) {
if (range.endIndex + i < range.count) {
defaultIndexes.push(range.endIndex + i);
}
}
}
return defaultIndexes;
}
function CustomRangeList({ items }: { items: any[] }) {
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
rangeExtractor: extraEndRangeExtractor,
});
return (
// Virtual list implementation
);
}import { useVirtualizer } from '@tanstack/react-virtual';
function DebugVirtualList({ items }: { items: any[] }) {
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
debug: process.env.NODE_ENV === 'development',
});
// Debug mode will log performance metrics to console
return (
// Virtual list implementation
);
}Install with Tessl CLI
npx tessl i tessl/npm-tanstack--react-virtual