JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeQuestionsreact
PrevNext

Learn the concept

Performance Optimization

react
senior
performance

How does list virtualization (windowing) work in React and when should you use it?

virtualization
windowing
performance
lists
infinite-scroll
Quick Answer

List virtualization renders only the items currently visible in the viewport plus a small overscan buffer, replacing thousands of DOM nodes with a handful. This dramatically reduces initial render time, memory usage, and DOM size for large lists.

Detailed Explanation

When rendering large lists (hundreds or thousands of items), creating a DOM node for every item causes significant performance problems: slow initial render, high memory usage, sluggish scrolling, and poor Interaction to Next Paint (INP). Virtualization (also called windowing) solves this by only rendering items visible in the viewport.

How Virtualization Works

  1. A scroll container has a fixed height (the viewport)
  2. A spacer element inside it has the full height of all items combined (creating the scrollbar)
  3. Only items within the visible area (plus a small overscan buffer above and below) are actually rendered as DOM nodes
  4. As the user scrolls, items entering the viewport are created and items leaving are destroyed
  5. Items are absolutely positioned using CSS transform: translateY() to appear at the correct scroll offset

This means a list of 10,000 items might only have 20-30 actual DOM nodes at any time.

Key Concepts

  • Overscan — Extra items rendered above and below the viewport to prevent flashing during fast scrolling. Typically 3-5 items.
  • Fixed vs variable height — Fixed-height items are simple (offset = index × height). Variable-height items require measuring each item or providing an estimated height function.
  • Scroll restoration — When items are removed and re-created during scrolling, scroll position must be maintained precisely.

Popular Libraries

| Library | Strengths | |---------|----------| | @tanstack/react-virtual | Headless, hooks-based, supports horizontal/grid virtualization, TypeScript-first | | react-window | Lightweight (6KB), simple API, successor to react-virtualized | | react-virtuoso | Auto-measures variable heights, built-in grouping, chat-style reverse scrolling | | react-virtualized | Feature-rich but large (25KB+), supports tables/grids/masonry |

When to Use Virtualization

  • Lists with 100+ items that are causing measurable performance issues
  • Infinite scroll feeds (social media timelines, product catalogs)
  • Large data tables with hundreds of rows
  • When INP or Total Blocking Time metrics are poor due to DOM size

When NOT to Virtualize

  • Lists with fewer than ~50-100 items — the overhead isn't worth it
  • When items need to be searchable by the browser (Ctrl+F won't find off-screen items)
  • When SEO matters — search engines may not see non-rendered items
  • When accessibility requires all items to be in the DOM (screen readers may not announce virtualized items correctly without ARIA attributes)

Implementation Considerations

  • Keyboard navigation — Ensure focus management works when scrolling with arrow keys
  • Dynamic content — Items that load images or expand need height recalculation
  • Scroll to index — Support jumping to a specific item (e.g., "scroll to bottom" in chat)
  • Sticky headers — Group headers that stay visible while scrolling through a section

Code Examples

Virtualized List with @tanstack/react-virtualTSX
import { useVirtualizer } from '@tanstack/react-virtual';
import { useRef } from 'react';

function VirtualList({ items }: { items: string[] }) {
  const parentRef = useRef<HTMLDivElement>(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50, // Estimated item height in px
    overscan: 5, // Render 5 extra items above/below viewport
  });

  return (
    <div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
      {/* Spacer div creates the full scrollable height */}
      <div style={{ height: `${virtualizer.getTotalSize()}px`, position: 'relative' }}>
        {virtualizer.getVirtualItems().map((virtualItem) => (
          <div
            key={virtualItem.key}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualItem.size}px`,
              transform: `translateY(${virtualItem.start}px)`,
            }}
          >
            {items[virtualItem.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

// Renders 10,000 items with only ~15 DOM nodes
<VirtualList items={Array.from({ length: 10000 }, (_, i) => `Item ${i}`)} />

Real-World Applications

Use Cases

E-commerce Product Grids

Product listing pages with thousands of items use virtualization to render only visible products, enabling infinite scroll without degrading performance.

Chat Applications

Messaging apps virtualize conversation history with reverse scrolling, loading older messages as users scroll up while keeping recent messages in view.

Mini Projects

Virtualized Data Grid

advanced

Build a data grid that virtualizes both rows and columns, supporting 10,000+ rows with sortable headers, row selection, and sticky first column.

Industry Examples

Flipkart

Uses a custom recyclerlistview for cross-platform list virtualization in their React Native mobile app, rendering thousands of product cards efficiently.

Resources

TanStack Virtual Documentation

docs

web.dev - Virtualize Long Lists

article

Related Questions

Explain React.memo, useMemo, and useCallback. When should each be used?

senior
performance

How would you design and implement a reusable Pagination component in React?

senior
patterns
Previous
How would you design and implement a reusable Pagination component in React?
Next
Explain React's hydration process and common hydration mismatch issues.
PrevNext