Build a Zero-Dependency List Virtualization Hook in React

You render 10,000 rows. The page freezes for a moment, the scrollbar stutters, and the browser tab's memory climbs. Nothing is wrong with your data fetching or your component logic. The browser is simply being asked to build, style, lay out and keep alive far more elements than any user can see at once.

List virtualization (also called windowing) fixes this by rendering only the rows near the viewport and faking the rest of the scroll height. The DOM stays small whether you have 500 rows or 500,000.

Libraries such as TanStack Virtual and react-window do this well. But building the mechanism once, from scratch, teaches you what those libraries are doing, helps you debug them, and gives you a tiny hook you fully control. In this guide we build a zero-dependency virtualization hook in React and TypeScript with:

  • Variable row heights, measured automatically with ResizeObserver
  • Binary-search lookups over a Float64Array, so finding the first visible row is O(log n)
  • Scroll position compensation, so late-measured rows don't make the list jump