Skip to content

CONCEPT Cited by 1 source

Window virtualization

Window virtualization (a.k.a. virtual scrolling / virtual lists) is a front-end rendering technique that keeps only the visible portion of a long list or grid in the DOM at any moment. As the user scrolls, off-screen items are unmounted (or never mounted) and new items are swapped in — the browser sees a constant-size DOM instead of a list-length-proportional one. See the background reference at patterns.dev/vanilla/virtual-lists.

Why it's needed

Rendering a naive list of N items costs O(N) in:

  • DOM nodes (memory + every browser-paint operation scales with node count).
  • JS heap (each component's state, handlers, closures).
  • Layout work (any layout pass traverses the whole tree).
  • Event handler count (if attached per-item).

At tens of thousands of items these costs cross product-unusable thresholds. GitHub's Files-changed tab pre-virtualization on a p95+ PR showed >1 GB JS heap, >400,000 DOM nodes, and INP in the 275-700+ ms range.

Mechanism

  • Scrollable viewport with a spacer element representing the full logical list height (so the scrollbar reflects true length).
  • Measured or uniform item heights — library knows what range of items maps to the current scroll position.
  • Render only that visible slice plus a small overscan buffer (typically a few screens) to hide mount/unmount flicker.
  • On scroll: compute new slice, mount new items, unmount items now off-screen.

The DOM cost becomes O(viewport-size), independent of list length.

Trade-offs

  • Native browser find-in-page sacrificed. Ctrl-F searches the DOM; content not in the DOM is invisible to it. GitHub's strategy explicitly accepts this on p95+ PRs and preserves it on median PRs (per-size-tier choice).
  • Accessibility risks. Screen readers sometimes read list structure differently when items are virtualized; ARIA relationships need explicit handling.
  • Scroll-position restoration across navigation is harder when items aren't persistently in the DOM.
  • Fixed vs dynamic item sizes. Dynamic sizes (diff lines with wrapping text, comments expanded inline) need measurement passes that cost extra work.
  • Library footprint. Adds a virtualization substrate (TanStack Virtual, react-window, react-virtuoso, etc.) that needs maintenance.

Canonical wiki instance

GitHub's pull-request Files-changed tab uses TanStack Virtual for p95+ PRs (>10,000 diff lines). Reported impact: 10× reduction in JS heap usage + DOM nodes, INP 275-700+ ms → 40-80 ms. (Source: sources/2026-04-03-github-the-uphill-climb-of-making-diff-lines-performant)

Server-side analogue

patterns/server-hydrate-visible-only — hydrate only the visible portion on the server-side-rendering pass, mirroring the client virtualization choice at the SSR layer. GitHub does both.

Last updated · 200 distilled / 1,178 read