Render 100,000 Rows Smoothly with Grid Virtualization - SvGrid blog illustration

Render 100,000 Rows Smoothly with Grid Virtualization

How SvGrid virtualizes rows and columns so a Svelte data grid stays at 60fps even with 100k rows by 100 columns.

A naive table renders one DOM row per data row. At a few thousand rows the browser slows; at a hundred thousand it locks up. SvGrid solves this with built-in row and column virtualization - only the cells in the viewport exist in the DOM.

It is on when it needs to be

Virtualization in SvGrid does not require special wiring. Give the grid a bounded height and a large data array, and it renders only the visible window plus a small overscan buffer.

<div style="height: 600px;">
  <SvGrid data={hundredThousandRows} columns={columns} />
</div>

The key detail is the bounded height. The grid needs to know its viewport to compute which rows are visible, so place it in a container with an explicit height or a flex layout that gives it one.

Why it stays fast

Keep your data layer fast too

Virtualization handles rendering, but your data still flows through the engine. A few habits keep the whole pipeline quick:

Sizing in a flex layout

A common gotcha is a grid with no height. Inside a flex column, give the grid flex: 1 and min-height: 0:

<div style="display:flex; flex-direction:column; height:100vh;">
  <header>Toolbar</header>
  <div style="flex:1; min-height:0;">
    <SvGrid data={rows} columns={columns} />
  </div>
</div>

Without min-height: 0, flex children refuse to shrink and the grid grows past the viewport, defeating virtualization.

How virtualization actually works

It helps to picture what the grid is doing on every scroll frame. Given the scroll position, the row height, and the viewport height, the grid computes the first and last visible row indices, adds a small overscan buffer above and below, and renders only that slice. As you scroll, the same pool of DOM rows is repositioned and refilled with new data rather than created and destroyed.

The consequences are worth internalizing:

Fixed vs variable row heights

Uniform row heights are the fast path: the grid can calculate any row's position with a single multiplication, so jumping to row 90,000 is instant. If your rows vary in height - wrapped text, expandable detail - the grid has to measure and track offsets, which is still fast but does more work. When you can, keep rows a consistent height and push variable content into a master-detail panel that only exists when expanded.

The overscan trade-off

Overscan is the buffer of off-screen rows the grid keeps rendered just beyond the viewport. A larger buffer means fewer blank flashes during very fast scrolling, at the cost of more DOM nodes. The defaults are tuned for the common case; you rarely need to touch them, but it is useful to know the dial exists if you are chasing the last few milliseconds on a low-end device.

Measuring it yourself

Do not take "it is fast" on faith - measure on the hardware your users actually have. A quick protocol:

  1. Open your browser's performance panel and record while scrolling the full height of the grid.
  2. Watch for long frames (over ~16ms) and layout thrash.
  3. Check the DOM node count in the Elements panel - it should stay roughly constant as you scroll.

If the node count climbs as you scroll, virtualization is not engaging - and the cause is almost always a missing height on the container.

Common pitfalls

Pairing with server-side data

Virtualization bounds the DOM; it does not bound the network. If your source is millions of rows, do not ship them all to the browser just because the grid can render them. Combine virtualization with server-side paging: the server bounds the data transferred, and virtualization bounds the DOM for whatever is loaded.

Frequently asked questions

Can a Svelte data grid handle 100,000 rows?

Yes. SvGrid virtualizes rows and columns, so a 100k by 100 grid keeps a small, constant DOM and scrolls smoothly. Give the grid a bounded height so it can compute the visible window.

Why is my virtualized grid not scrolling?

Almost always a height problem. The grid needs an explicit height or a flex parent with min-height: 0. Without it the grid cannot determine its viewport.