DEV Community

Cover image for Virtualisation with TanStack Virtual
Oluwatomisin Oyemade
Oluwatomisin Oyemade

Posted on

Virtualisation with TanStack Virtual

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.

But why do we need Virtualisation?

Why Virtualisation Is Essential

When handling extensive datasets:

  1. Memory consumption: Rendering numerous DOM elements utilises a considerable amount of memory.

  2. Initial rendering speed: The initial display slows down as React builds and reconciles a large tree.

  3. Scrolling responsiveness: Working with large datasets increases the workload and DOM size, leading to sluggish scrolling.

  4. User experience: It might look as though the application is malfunctioning, even though it works properly, because of the slow response when scrolling and tapping.

Virtualisation significantly reduces 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 prebuilt UI components. Instead, it provides the virtualisation engine (including ranges, offsets, total size, and measurement utilities), allowing you to maintain complete control over your markup, styling, layout, and interactions. This offers a significant benefit when your list items are not just basic rows but also intricate UI elements such as badges, menus, images, buttons, and complex designs.

Let’s get it set up in your project.

Installation

npm install @tanstack/react-virtual
Enter fullscreen mode Exit fullscreen mode

or

yarn add @tanstack/react-virtual
Enter fullscreen mode Exit fullscreen mode

or

pnpm add @tanstack/react-virtual
Enter fullscreen mode Exit fullscreen mode

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:

  1. Scroll container – a div with a fixed height and overflow: auto
  2. Spacer – an inner element with the total list height (getTotalSize())
  3. Virtual items – only the visible items, positioned using transform: translateY(...)

Example:

import { useVirtualizer } from "@tanstack/react-virtual";

export function BasicVirtualList() {
  const parentRef = React.useRef<HTMLDivElement | null>(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: 450,
        overflow: "auto",
        border: "1px solid #e5e7eb",
        borderRadius: 12,
      }}
    >
      <div
        style={{
          height: virtualizer.getTotalSize(),
          position: "relative",
        }}
      >
        {virtualizer.getVirtualItems().map((vItem) => (
          <div
            key={vItem.key}
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: vItem.size,
              transform: `translateY(${vItem.start}px)`,
              display: "flex",
              alignItems: "center",
              padding: "0 12px",
              borderBottom: "1px solid #f3f4f6",
              boxSizing: "border-box",
            }}
          >
            {items[vItem.index]}
          </div>
        ))}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

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 coming in) 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: Using a fixed layout is usually more straightforward, while a variable one means you’ll need to measure and manage sizes carefully.

  • Row state: Virtualised rows may mount and unmount as you scroll. Make sure any 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, which can cause scroll jumps if not treated carefully.

  • Performance proof: Check the results before and after using the React Profiler and Chrome Performance tools.

Common Pitfalls (And How to Avoid Them)

Even when following best practices, virtualised lists can introduce subtle bugs and performance issues. Here are some common issues and their solutions.

  • Blank gaps during rapid scrolling:
Increase the overscan slightly 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 allow accurate measurement to prevent scroll position shifts due to dynamic height changes.

  • Losing row state:
Lift the state and store it by id. Avoid keeping crucial state solely inside row components, as they may mount and unmount during scrolling.

  • Wrong keys:
Use stable keys with getItemKey when the list order might change. Do not rely on array indices

Wrap Up

Virtualisation is among the most effective performance improvements you can implement for extensive lists in React. With TanStack React Virtual, you receive a versatile, headless engine that integrates smoothly into actual applications—particularly when you desire complete control over the UI layout.

Top comments (0)