Virtualisation with TanStack Virtual
Source: Dev.to
Optimising performance is a common topic in the React community. Users expect smooth scrolling and quick interactions, especially when handling large datasets that can grow to thousands of entries.
Virtualisation improves large lists by displaying only the visible elements (plus a small buffer) rather than loading thousands of DOM elements all at once. As the user scrolls, elements are added and removed dynamically, while the list maintains the appearance of a fully rendered dataset without any drop in performance.
Why Virtualisation Is Essential
When handling extensive datasets:
- Memory consumption – Rendering numerous DOM elements utilises a considerable amount of memory.
- Initial rendering speed – The initial display slows down as React builds and reconciles a large tree.
- Scrolling responsiveness – Working with large datasets increases the workload and DOM size, leading to sluggish scrolling.
- User experience – The application may feel malfunctioning because of the slow response when scrolling and tapping.
Virtualisation significantly reduces the DOM node count, often resulting in smoother scrolling and faster interactions. Various methods exist for implementing virtualisation in React. In this piece, we’ll concentrate on TanStack Virtual.
Introduction to TanStack Virtual
TanStack Virtual is a headless virtualisation library. It does not include pre‑built UI components. Instead, it provides the virtualisation engine (ranges, offsets, total size, and measurement utilities), allowing you to maintain complete control over your markup, styling, layout, and interactions. This is especially valuable when your list items are not just basic rows but also intricate UI elements such as badges, menus, images, buttons, and complex designs.
Installation
npm install @tanstack/react-virtual
# or
yarn add @tanstack/react-virtual
# or
pnpm add @tanstack/react-virtual
Understanding TanStack Virtual Fundamentals
TanStack Virtual isn’t a UI component library you drop into your app and forget about. It’s a lightweight utility that handles the hard part of virtualisation, determining:
- which items should be visible,
- where those items should be positioned in the scroll space,
- and how large the full list should appear (so the scrollbar behaves naturally).
You still build the UI yourself: your markup, styling, layout, and interactions.
Now, let’s analyse it step by step.
Mental Model (the “Illusion”)
A virtual list usually has three pieces:
- Scroll container – a
divwith a fixed height andoverflow: auto. - Spacer – an inner element with the total list height (
getTotalSize()). - Virtual items – only the visible items, positioned using
transform: translateY(...).
Example
import { useVirtualizer } from "@tanstack/react-virtual";
export function BasicVirtualList() {
const parentRef = React.useRef(null);
const items = React.useMemo(
() => Array.from({ length: 100_000 }, (_, i) => `Item ${i + 1}`),
[]
);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 44, // fixed row height
overscan: 8,
});
return (
<div ref={parentRef} style={{ height: "400px", overflow: "auto" }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map((vItem) => (
<div
key={vItem.key}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: `${vItem.size}px`,
transform: `translateY(${vItem.start}px)`,
}}
>
{items[vItem.index]}
</div>
))}
</div>
</div>
);
}
Key Concepts You’ll Use in Every Implementation
estimateSize– A function that returns an estimated item height (or width for horizontal lists).getItemKey– Utilise consistent keys when your list might change (due to sorting, filtering, or new data) to guarantee that virtualisation stays stable.overscan– Controls the number of extra items that render above and below the viewport. Higher overscan reduces blank gaps during fast scrolling, but increases work per scroll.
Aside from configuration, practical factors can influence the effectiveness of virtualisation in your application.
Tips for Virtualisation
- Fixed vs. variable item height – Fixed layouts are simpler; variable heights require measuring and managing sizes carefully.
- Row state – Virtualised rows may mount and unmount as you scroll. Ensure critical data or state isn’t stored only inside the row components themselves.
- Focus & accessibility – When a row is unmounted, input and keyboard navigation may break if focus disappears.
- Images and dynamic content – Media that loads slowly can change heights, causing scroll jumps if not handled properly.
- Performance proof – Compare results before and after using the React Profiler and Chrome Performance tools.
Common Pitfalls (And …)
Content for this section can be added later.
How to Avoid Them
Even when following best practices, virtualised lists can introduce subtle bugs and performance issues. Below are some common problems and their solutions.
-
Blank gaps during rapid scrolling
Increase theoverscanslightly so that more items are rendered beyond the visible viewport. -
Scroll jumps with variable content
Reserve space for images by setting a fixed height or aspect‑ratio, or enable accurate measurement to prevent scroll‑position shifts caused by dynamic height changes. -
Losing row state
Lift the state and store it byid. Avoid keeping crucial state solely inside row components, as they may mount and unmount during scrolling. -
Wrong keys
Use stable keys withgetItemKeywhen the list order might change. Do not rely on array indices.
Wrap Up
Virtualisation is one of the most effective performance improvements you can implement for extensive lists in React. With TanStack React Virtual, you get a versatile, headless engine that integrates smoothly into real applications—especially when you need complete control over the UI layout.