Virtualization

The problem

The naive approach to rendering a 50,000-row data grid is to create 50,000 DOM nodes. The browser then spends its time laying out, painting, and reflowing elements the user can’t even see. Virtualization (also called windowing) fixes this by rendering only the rows currently visible in the viewport, plus a small buffer above and below for smooth scrolling.

Libraries like react-window and TanStack Virtual provide the infrastructure. For complex enterprise grids with frozen columns, dynamic row heights, and horizontal scrolling across hundreds of columns, teams often build a custom implementation tuned to their data shape, or adopt AG Grid. We use AG Grid at Coinbase for internal, data-heavy apps; it's excellent and highly customizable.

See the difference

Two inboxes, the same 10,000 messages, scrolling together. Render every row on the left and watch what it costs to build them. The list on the right never builds more than fourteen, however far you scroll.

Naiverender every row
Nothing is mounted yet.
0rows in the DOM
Virtualizedrender the window
ACAva ChenRe: Q3 roadmap review1:00 AM#1
LSLiam SilvaNew comment on your doc2:17 AM#2
NRNoah RossiPayment received3:34 AM#3
ESEmma SinghCan you review this PR?4:51 AM#4
OCOlivia CostaDeploy succeeded5:08 AM#5
EMEthan MoriWelcome to the team!6:25 AM#6
MAMia AzizDesign feedback needed7:42 AM#7
LKLucas KimYour order has shipped8:59 AM#8
ANAria NguyenReminder: 1:1 at 3pm9:16 AM#9
LLLeo LopezRe: bug in checkout10:33 AM#10
ZAZoe AdlerLunch on Friday?11:50 AM#11
11rows in the DOM

Both lists hold the same 10,000 messages and scroll together. Only one of them builds 10,000 elements to do it.

Fixed versus variable height

Fixed height is trivial: every offset is index * ROW_H. Variable height must be measured: render with an estimate, measure the real height after layout, cache it by index, and anchor the scroll position so a re-measured row does not make the list jump.

Trade-offs

You take back behaviors the browser handled for free:

  • Ctrl or Cmd + F only finds mounted rows.
  • Linking or scrolling to an off-screen row needs manual offset math.
  • Keep list semantics intact and do not strand focus on an unmounted row.
  • Drag and drop reorders by data, since the target may be unmounted.

Reach for a library (react-window, @tanstack/react-virtual, react-virtuoso); hand-roll only to learn or customize.

Why interviewers ask this

"The list could have thousands of items" is a standard scaling turn, and virtualization is the expected answer. It shows you know rendering cost scales with DOM size, not screen size. It recurs in feed, chat, table, and board questions.