Virtualization
Asked In
Key Challenges
- ·Rendering 10k+ rows without freezing the main thread
- ·Measuring variable row heights without scroll jumps
- ·Keeping focus and find-in-page usable with a windowed DOM
- ·Knowing when virtualization is the wrong tool
Guided Answer
Read this path first — then deepen in RADIO below
Simple Explanation
Imagine a notifications list with 50,000 rows.
The first paint looks fine. Then the user scrolls — the tab freezes, the fan spins, and the page feels broken.
Virtualization fixes this. You only put the rows on screen into the DOM. The rest of the list is empty scroll space, not real elements.
Mental Model
Think of a theater that only lights the seats people can see.
You keep a tall empty spacer for the full list height. Inside it, you mount ~20–40 visible rows (plus a little overscan above and below). When the user scrolls, you slide that window. Fixed row height = simple math. Variable height = estimate, measure, cache, then re-anchor so the list does not jump.
Diagrams
data.map — (Row)
50,000 DOM nodes
lag on every scroll
read scrollTop + viewport
compute startIndex / endIndex + overscan
mount only that slice inside the spacer
variable height: estimate — measure → cache → re-anchor
Step-by-Step
Scene — the laggy list
Product dumps tens of thousands of rows into a table or feed. Scrolling hitchs. That is your opening story — not a library name.
Say this
“I would start from DOM cost: layout scales with mounted nodes, not with how many rows exist in data.”
Naive move
Render everything with data.map(Row). Fine for 30 rows in Storybook. Dies at 10k+ because every scroll pays for the whole list.
- ·Long freezes while scrolling
- ·Memory grows with list length
- ·Updates and focus get expensive
Say this
“The naive .map() breaks when cost follows list length instead of screen size.”
The fix — window + spacer + overscan
Track scroll position and viewport height. Compute which indexes are visible. Render only that slice inside a tall spacer that represents the full list. Overscan adds a few extra rows so fast flings do not flash empty space.
totalHeight = count * rowHeight start = floor(scrollTop / rowHeight) - overscan end = ceil((scrollTop + viewport) / rowHeight) + overscan
Say this
“I keep a spacer for total height and only mount the visible index range plus overscan.”
Variable heights
Chat bubbles are not one height. Estimate first, measure after paint, cache by index, then fix the spacer. If a row above the viewport changes height, re-anchor scroll so the row under the user's eyes does not jump.
Say this
“For variable rows I estimate, measure, cache, and re-anchor — otherwise the list jumps.”
Trade-offs to say out loud
Browser find (Cmd/Ctrl+F) only sees mounted rows. scrollToId needs your height model. Focus cannot assume every row exists. Call these out before the interviewer asks.
- ·Find-in-page is incomplete
- ·scrollToId needs cached offsets
- ·Sticky headers need extra care
Say this
“I would mention find-in-page, focus, and scroll-to-id as trade-offs up front.”
When NOT to virtualize
Skip it for a 15-item dropdown, a short settings page, or print layouts. Virtualization has cost — measurement bugs and harder tests. Use it when DOM budget is the real problem.
Say this
“I would not virtualize a small list — the complexity is not free.”
Final Answer
I keep DOM cost tied to the viewport. A VirtualList tracks scrollTop, computes a visible range with overscan, and places those rows inside a spacer for total height. Fixed heights use simple math. Variable heights use estimate → measure → cache → re-anchor. I call out find-in-page and focus trade-offs, and I skip virtualization for small lists.
Deep Dive — RADIO Framework
2-Minute Answer — High-Level TL;DR
Read this before your interview
HLD Interview Focus
I would not mount ten thousand DOM nodes for a feed or table. Virtualization keeps only the visible window plus a small overscan band in the DOM. I track scrollTop, compute start/end indexes from row heights, and absolute-position those rows inside a tall spacer that represents total height. For variable heights I estimate, measure after paint, cache by index, and re-anchor so a remeasure does not jump the list. I would not virtualize a 20-item dropdown.
My Approach: Building the Solution
How to think about this problem
Start from the failure: a product manager dumps 50k notifications into a list and the tab locks for half a second on every scroll. Then show the windowing fix before naming a library.
Why This Approach?
Junior answers call .map() and hope. That dies when layout/paint scale with list length. Staff answers window the list, explain overscan, and volunteer trade-offs (Cmd-F, focus, scroll-to-id) before the interviewer fishes for them.
A theater only lights the seats people can see. Virtualization lights the viewport — the rest of the audience exists as empty space in the scrollable stage, not as real chairs.
Requirements: What Makes a Great Solution?
Clarify scope before designing anything
Requirements Exploration Questions
Ask your interviewer these questions to refine requirements
How large is the list, really?
- ·Hundreds, thousands, or hundreds of thousands?
- ·Fixed vs variable row height?
- ·Horizontal virtualization needed?
What interactions must survive windowing?
- ·Scroll to item by id
- ·Keyboard focus
- ·Sticky headers
- ·Find-in-page
Functional Requirements
Must Have — MVP
- ✓Viewport window + overscan
- ✓Spacer height = sum of row heights
- ✓Scroll position → visible index range
- ✓Stable keys for mounted rows
Advanced (If Time Permits)
- +Dynamic measurement cache
- +Two-axis virtualization (spreadsheet)
- +Sticky columns/headers with virtualized body
Non-Functional Requirements
Interview bar
- ·Name the invariant in one sentence
- ·Give one concrete failure of the naive approach
- ·State when the pattern is the wrong tool
Architecture (Conceptual)
Component structure, data flow, rendering strategy
Virtualized Data Table Engine
10,000 Records • Real-time Sort & Filter • Fixed DOM SliceComponent Hierarchy
Top-Level: VirtualList
- ·Compute visible range from scrollTop + viewport
- ·Maintain height estimates and measured cache
- ·Position rows; expose scrollToIndex
React-Specific Architecture Patterns
VirtualList
- ·Compute visible range from scrollTop + viewport
- ·Maintain height estimates and measured cache
- ·Position rows; expose scrollToIndex
Why React Query + Zustand?
Keep teaching state next to the concept; libraries are secondary.
Data Model (API + Entities + Cache)
Entities, interfaces, cache shape, consistency rules
Minimal entities that make the concept concrete in code reviews and whiteboards.
HeightModel
Interface Design (React Integration)
API contracts, hooks, integration patterns
Contracts are light for core concepts — prove the idea, not a full product API.
Optimization (Performance + Scale)
Rendering, media, network, and memory optimizations
I would not mount ten thousand DOM nodes for a feed or table. Virtualization keeps only the visible window plus a small overscan band in the DOM. I track scrollTop, compute start/end indexes from row heights, and absolute-position those rows inside a tall spacer that represents total height. For variable heights I estimate, measure after paint, cache by index, and re-anchor so a remeasure does not jump the list. I would not virtualize a 20-item dropdown.
Sticky rules
- ·DOM cost scales with mounted nodes — virtualize so only the viewport (+ overscan) exists.
- ·Estimate → measure → cache height → re-anchor scroll, or variable rows will jump.
- ·Overscan buys smoothness; too much overscan recreates the original problem.
- ·Do not virtualize small lists — complexity is not free.
Optimistic Updates
Junior answers call .map() and hope. That dies when layout/paint scale with list length. Staff answers window the list, explain overscan, and volunteer trade-offs (Cmd-F, focus, scroll-to-id) before the interviewer fishes for them.
Remember
DOM cost scales with mounted nodes — virtualize so only the viewport (+ overscan) exists.
Say this in the interview
“I would not mount ten thousand DOM nodes for a feed or table.”
Bonus: Implementation Cookbook (Optional)
LLD snippets — only when asked by interviewer
Follow-ups interviewers use after you nail the core idea.
Included (Minimal)
- ·Dynamic measurement cache
- ·Two-axis virtualization (spreadsheet)
- ·Sticky columns/headers with virtualized body
Key Takeaways
- ✓DOM cost scales with mounted nodes — virtualize so only the viewport (+ overscan) exists.
- ✓Estimate → measure → cache height → re-anchor scroll, or variable rows will jump.
- ✓Overscan buys smoothness; too much overscan recreates the original problem.
- ✓Do not virtualize small lists — complexity is not free.