React Curriculum

List Virtualization & Windowing Strategies

Hard100% Free~30 mins#react#virtualization#windowing#react-window#dom-performance#scrolling
Interview Answer (30-Second Summary)

List virtualization (windowing) renders only the subset of items currently visible in the browser viewport (plus a small overscan buffer), recycling DOM nodes as the user scrolls. It keeps DOM node counts constant (e.g. 20 elements) even for lists of 100,000 items.

Key Learning Objectives
✓

Explain why rendering 10,000 DOM nodes crashes mobile browser performance and destroys memory.

✓

Implement the core mathematical formulas of virtualization: startIndex, endIndex, and offsetY.

✓

Explain the purpose of an overscan buffer for smooth scrolling without white flashes.

✓

Differentiate fixed-size virtualization from dynamic variable-height virtualization.

The Interview Problem & Context

Implement the core mathematical windowing calculations for a fixed-size virtualized list of 10,000 items (itemHeight = 50px, containerHeight = 400px).

1export interface VirtualWindowParams {
2 totalItems: number;
3 itemHeight: number;
4 containerHeight: number;
5 scrollTop: number;
6 overscan?: number;
7}
8
9export function calculateVirtualWindow({
10 totalItems,
11 itemHeight,
12 containerHeight,
13 scrollTop,
14 overscan = 2,
15}: VirtualWindowParams) {
16 const totalHeight = totalItems * itemHeight;
17
18 // 1. Calculate visible range
19 const rawStartIndex = Math.floor(scrollTop / itemHeight);
20 const visibleCount = Math.ceil(containerHeight / itemHeight);
21
22 // 2. Add overscan buffer
23 const startIndex = Math.max(0, rawStartIndex - overscan);
24 const endIndex = Math.min(totalItems - 1, rawStartIndex + visibleCount + overscan);
25
26 // 3. Top offset to position visible slice correctly
27 const offsetY = startIndex * itemHeight;
28
29 return {
30 totalHeight,
31 startIndex,
32 endIndex,
33 offsetY,
34 renderedCount: endIndex - startIndex + 1,
35 };
36}
Deep Architectural Explanation

The Mechanics of List Virtualization

When rendering a list of 50,000 items:

  • Native rendering: Creates 50,000 DOM nodes. The browser consumes 500MB of RAM, styles freeze, and scrolling stutters at 5fps.
  • Virtualized rendering: Creates only ~15 DOM nodes (enough to fill the viewport). Memory usage drops to 1MB, maintaining a steady 60fps!

The Mathematical Engine

  1. Total Height: totalHeight = totalItems * itemHeight. This is applied to an invisible inner spacer so the browser scrollbar reflects the true full height of the list.
  2. Start Index: Math.floor(scrollTop / itemHeight).
  3. Visible Count: Math.ceil(containerHeight / itemHeight).
  4. Overscan Buffer: A buffer of 2–5 items above and below the viewport rendered ahead of time so fast scrolling doesn't show blank white space.
  5. Top Offset: startIndex * itemHeight applied via transform: translateY(${offsetY}px) to position the visible items correctly inside the scrolled view.
Common Interview Traps & Pitfalls
✕

Not including an outer scroll container with overflow: auto and relative positioning.

✕

Using top: ${offsetY}px instead of transform: translateY() (transforms avoid forced synchronous reflows).

✕

Forgetting the overscan buffer, causing visual flashing during fast scrolling.

Senior Interviewer Follow-Up Probes
?

How do you measure dynamic variable-height items in virtualized lists (using ResizeObserver)?

?

How does list virtualization handle keyboard focus and screen readers accessibly?

?

How does TanStack Virtual compare to react-window?

Frequently Asked Interview Questions
What is list virtualization in React?

A performance technique that only renders DOM elements currently visible inside the viewport window, calculating offsets mathematically as the user scrolls.

CSS transforms are composited on the GPU without triggering browser layout or repaint passes, whereas mutating top forces layout reflows.

A small number of extra items rendered just outside the visible viewport boundaries to prevent blank white flashes during fast scrolling.

A dummy inner container is given an explicit height equal to totalItems * itemHeight, tricking the browser scrollbar into displaying the true list proportion.

Estimate height initially, measure rendered nodes using ResizeObserver or getBoundingClientRect, and maintain a dynamic position cache of accumulated heights.