Setting directDomUpdates: true allows the virtualizer to skip React re-renders for scroll-only updates. Instead of waiting for a React render cycle, the virtualizer writes item positions and container dimensions directly to the DOM.
Requirements for directDomUpdates:
- Item Elements: Must have
position: absolute. If using directDomUpdatesMode: 'transform', they must also be anchored with top: 0 and left: 0. - Item Styles: You must not set the main-axis position (
top/left or transform) in your JSX; the virtualizer manages this. - Container: The inner size container must receive
virtualizer.containerRef and must not have height or width set in its style. - Multi-lane layouts: For grids/masonry, you must still manually set the cross-axis position (e.g.,
left) in your JSX.
⚠️ Warning: This flag should be set once at mount. Toggling it at runtime can leave stale inline styles on items and the container.
Note: If you omit containerRef, the virtualizer will not perform direct DOM writes for the container size or item positions, but you still benefit from skipped re-renders.
const virtualizer = useVirtualizer({
count: 10000,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
directDomUpdates: true,
})
return (
<div ref={parentRef} style={{ overflow: 'auto', height: 400 }}>
{/* The inner container must use virtualizer.containerRef and not set height */}
<div ref={virtualizer.containerRef} style={{ position: 'relative' }}>
{virtualizer.getVirtualItems().map((item) => (
<div
key={item.key}
ref={virtualizer.measureElement}
data-index={item.index}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
// Do NOT set top/left/transform — the virtualizer handles it
}}
>
Row {item.index}
</div>
))}
</div>
</div>
)