When to use: Fixed rows or columns whose dimensions never change.
How: Return the known size from estimateSize and apply the same size when positioning the item. For variable but known data, return rows[index]. For content that changes after render, use measureElement with data-index, or resizeItem when the final size is known externally.
Trade-offs: Fixed or known sizes are stable and cheap. DOM measurement handles real content but can cause correction work and requires careful layout. Do not use both sizing owners on one index.
When to use: Every scrollable virtualizer that must avoid blank gaps during fast movement.
How: Start with the examples' values: 5 for ordinary lists, 6 for chat, and 20 for a costly table with a large rendered row workload. Increase for faster scrolling or expensive layout gaps; decrease when render cost dominates.
Trade-offs: More overscan improves continuity but renders more nodes.
When to use: Grouped lists where the active group header must remain visible.
How: Find the latest sticky index at or before range.startIndex, union it with defaultRangeExtractor(range), and render the sticky item without its normal transform, with a background and elevated zIndex.
Trade-offs: The sticky item is rendered outside its natural position and needs collision or next-header handling in the UI.
When to use: Paginated data with more pages available.
How: Set count to allRows.length + 1 while hasNextPage is true. Inspect the last virtual item and call fetchNextPage() when it reaches the end, guarded by isFetchingNextPage.
Trade-offs: A sentinel row participates in sizing and rendering; fetch state and errors remain application concerns.
When to use: Chat, AI streams, logs, and reverse feeds.
How: Use stable record keys, anchorTo: 'end', followOnAppend, a threshold such as 80 pixels, and measureElement for growing messages. Prepend older messages normally.
Trade-offs: End anchoring has a more specific scroll contract. Add a "latest" affordance when the reader is away from the end.
When to use: Large tables or grids where both rows and columns exceed practical DOM size.
How: Create one vertical and one horizontal virtualizer. Render their Cartesian product, set the inner height and width from each getTotalSize(), and translate cells on both axes.
Trade-offs: Rendered cells are the product of visible rows and columns. Keep overscan controlled.
When to use: The page window, rather than a nested element, owns scrolling.
How: Use useWindowVirtualizer, measure the list's page offset, pass it as scrollMargin, and subtract that margin from the item transform.
Trade-offs: Page layout and offset changes must be reflected in the margin.
When to use: Text-heavy rows whose height is determined by wrapping.
How: Cache prepare() by text and style, rerun layout() for width, and call virtualizer.measure() after width or font changes. Keep CSS and canvas inputs identical.
Trade-offs: Pretext cannot own images, embeds, or arbitrary component layout and needs Canvas 2D plus Intl.Segmenter.