🍪 TechCookies
HomeDSASystem DesignMy Progress
Free
Log inStart free
TechCookies — Practice · Learn · PrepareTechCookies — Practice · Learn · Prepare
ConceptsPracticeSD challengesPricingPrivacyTermsContact
© 2026 TechCookies
📚Virtualisation and Large ListsFree
7 sections
~26 min total
30 quick quizzes
4 SD challenges linked
0 of 7 done·~24 min left
Concepts›Virtualisation and Large Lists›What is Virtualisation and Large Lists?
0 / 7
0%
7 sections~26 min
1
What is Virtualisation and Large Lists?
Render only visible items to handle thousands of DOM nodes efficiently
Read
~4 min
⋯
Why the DOM Can't Hold 10,000 Nodes Efficiently
Large DOMs consume excessive memory, force expensive layout calculations, and degrade scroll performance dramatically
ReadQuiz
~4 min
⋯
How Virtualisation Works: The Core Idea
Windowing technique renders only visible items plus small overscan buffer, keeping DOM size constant regardless of data size
ReadQuizCode
~4 min
⋯
react-window vs TanStack Virtual
react-window offers simple component API; TanStack Virtual provides headless hooks for maximum control and framework flexibility
ReadQuizCode
~4 min
⋯
Variable Height Virtualisation
Handle rows with unknown heights using measurement callbacks and dynamic offset calculation instead of fixed-size math
ReadQuizCode
~4 min
⋯
Scroll Position Restoration on Back-Navigation
Store and restore scroll position when users navigate back to prevent losing their place in virtualised lists
ReadQuizCode
~4 min
⋯
Practice test
30 questions
~10 min
Section 1 of 7Read
What is Virtualisation and Large Lists?
Render only visible items to handle thousands of DOM nodes efficiently
~4 min read

Virtualisation and Large Lists

Virtualisation is one of the most powerful performance techniques in modern front-end development. When you have thousands of items to display — a news feed, a photo grid, a chat history — rendering all of them at once would freeze the browser. Virtualisation solves this by rendering only the items the user can currently see, keeping the DOM lean and the experience smooth. This guide walks you through why this matters, how to implement it, and how to think about it in system design interviews — starting from absolute zero.


What Is the DOM?

The Document Object Model (DOM) is the browser's in-memory representation of your HTML page. Every <div>, <p>, <img>, and <li> is a node in a giant tree. The browser must track every single one.

What Happens When You Render 10,000 Items?

Imagine you fetch 10,000 tweets and render them all at once:

<!-- Simplified example: rendering all items -->
<ul>
  <li>Tweet 1</li>
  <li>Tweet 2</li>
  <!-- ... 9,998 more ... -->
  <li>Tweet 10,000</li>
</ul>

The browser must:
1. **Parse** all 10,000 elements into DOM nodes
2. **Calculate styles** for every node (CSS matching)
3. **Perform layout** — calculate the position and size of each element (reflow)
4. **Paint** — draw pixels for every element
5. **Composite** — combine all layers onto the screen

Even if only 20 items are visible, all 10,000 exist in memory and participate in layout calculations.

### The Four Bottlenecks Explained

<svg viewBox="0 0 800 420" width="100%" xmlns="http://www.w3.org/2000/svg">
  <rect width="800" height="420" fill="#f8fafc" rx="12"/>
  <text x="400" y="35" text-anchor="middle" font-size="18" font-weight="bold" fill="#0f172a" font-family="sans-serif">Four Bottlenecks of a Large DOM</text>

  <!-- Memory -->
  <rect x="30" y="60" width="165" height="320" rx="10" fill="#fef2f2" stroke="#fca5a5" stroke-width="2"/>
  <text x="112" y="90" text-anchor="middle" font-size="14" font-weight="bold" fill="#dc2626" font-family="sans-serif">1. Memory</text>
  <text x="112" y="115" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">Each DOM node</text>
  <text x="112" y="132" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">stores properties,</text>
  <text x="112" y="149" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">event listeners,</text>
  <text x="112" y="166" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">computed styles.</text>
  <text x="112" y="195" text-anchor="middle" font-size="13" fill="#dc2626" font-family="sans-serif">~1–2 KB/node</text>
  <text x="112" y="215" text-anchor="middle" font-size="13" fill="#dc2626" font-family="sans-serif">x 10,000 nodes</text>
  <text x="112" y="240" text-anchor="middle" font-size="13" font-weight="bold" fill="#991b1b" font-family="sans-serif">= 10–20 MB</text>
  <text x="112" y="270" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">just for DOM,</text>
  <text x="112" y="287" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">before images</text>
  <text x="112" y="304" text-anchor="middle" font-size="11" fill="#7f1d1d" font-family="sans-serif">or other assets</text>

  <!-- Reflow -->
  <rect x="210" y="60" width="165" height="320" rx="10" fill="#fff7ed" stroke="#fdba74" stroke-width="2"/>
  <text x="292" y="90" text-anchor="middle" font-size="14" font-weight="bold" fill="#ea580c" font-family="sans-serif">2. Reflow</text>
  <text x="292" y="115" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">Changing one</text>
  <text x="292" y="132" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">element can force</text>
  <text x="292" y="149" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">the browser to</text>
  <text x="292" y="166" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">recalculate sizes</text>
  <text x="292" y="183" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">of ALL siblings.</text>
  <text x="292" y="215" text-anchor="middle" font-size="12" fill="#ea580c" font-family="sans-serif">10,000 items</text>
  <text x="292" y="235" text-anchor="middle" font-size="12" fill="#ea580c" font-family="sans-serif">= 10,000 layout</text>
  <text x="292" y="255" text-anchor="middle" font-size="12" fill="#ea580c" font-family="sans-serif">calculations</text>
  <text x="292" y="285" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">Can block the</text>
  <text x="292" y="302" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">main thread</text>
  <text x="292" y="319" text-anchor="middle" font-size="11" fill="#7c2d12" font-family="sans-serif">for seconds</text>

  <!-- Paint -->
  <rect x="390" y="60" width="165" height="320" rx="10" fill="#fefce8" stroke="#fde047" stroke-width="2"/>
  <text x="472" y="90" text-anchor="middle" font-size="14" font-weight="bold" fill="#ca8a04" font-family="sans-serif">3. Paint</text>
  <text x="472" y="115" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">The browser must</text>
  <text x="472" y="132" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">turn every node</text>
  <text x="472" y="149" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">into pixels on</text>
  <text x="472" y="166" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">the screen.</text>
  <text x="472" y="195" text-anchor="middle" font-size="12" fill="#ca8a04" font-family="sans-serif">Off-screen items</text>
  <text x="472" y="215" text-anchor="middle" font-size="12" fill="#ca8a04" font-family="sans-serif">still consume</text>
  <text x="472" y="235" text-anchor="middle" font-size="12" fill="#ca8a04" font-family="sans-serif">GPU memory</text>
  <text x="472" y="265" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">Especially bad</text>
  <text x="472" y="282" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">on mobile with</text>
  <text x="472" y="299" text-anchor="middle" font-size="11" fill="#713f12" font-family="sans-serif">limited GPU RAM</text>

  <!-- Scroll -->
  <rect x="570" y="60" width="165" height="320" rx="10" fill="#f0fdf4" stroke="#86efac" stroke-width="2"/>
  <text x="652" y="90" text-anchor="middle" font-size="14" font-weight="bold" fill="#16a34a" font-family="sans-serif">4. Scroll Jank</text>
  <text x="652" y="115" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">Scrolling fires</text>
  <text x="652" y="132" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">events rapidly.</text>
  <text x="652" y="149" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">With 10,000 nodes</text>
  <text x="652" y="166" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">each scroll event</text>
  <text x="652" y="183" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">triggers layout</text>
  <text x="652" y="200" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">recalculation.</text>
  <text x="652" y="230" text-anchor="middle" font-size="12" fill="#16a34a" font-family="sans-serif">Target: 60 FPS</text>
  <text x="652" y="250" text-anchor="middle" font-size="12" fill="#16a34a" font-family="sans-serif">= 16ms per frame</text>
  <text x="652" y="280" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">Large lists blow</text>
  <text x="652" y="297" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">this budget</text>
  <text x="652" y="314" text-anchor="middle" font-size="11" fill="#14532d" font-family="sans-serif">immediately</text>

  <!-- Bottom label -->
  <text x="400" y="400" text-anchor="middle" font-size="12" fill="#64748b" font-family="sans-serif">All four bottlenecks worsen linearly as the node count grows</text>
</svg>

### A Simple Mental Model

Think of the DOM like a restaurant kitchen. If you ask the kitchen to **prep all 10,000 dishes** on the menu at once — even though only 10 customers are ordering — the kitchen grinds to a halt. Virtualisation means: **only prep what is currently being ordered**.

### Measuring the Problem

```javascript
// Bad: renders everything at once
function BadList({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
}

// How many DOM nodes does this create?
// If items.length = 10,000 → 10,001 DOM nodes (10,000 <li> + 1 <ul>)
// Chrome DevTools → Performance tab → Nodes metric

**Rule of thumb:** The browser starts struggling noticeably around **1,000–1,500 DOM nodes** in a single scrollable list. At 10,000, most devices experience visible jank.

---

Mark this section complete.
Notes
🔍
Loading…