Virtual Scrolling

Configure large viewports, overscan, and programmatic scrolling.

ZenGrid virtualizes the viewport so only visible cells and overscan cells are rendered.

Basic Setup

virtual-grid.ts
const grid = new Grid(document.getElementById('grid')!, {
columns,
rowCount: rows.length,
colCount: columns.length,
rowHeight: 36,
colWidth: columns.map((column) => column.width ?? 140),
overscanRows: 10,
overscanCols: 5,
enableCellPooling: true,
});
grid.setData(rows);
grid.render();

Container Size

grid.css
#grid {
width: 100%;
height: 640px;
}
Warning

The container must have dimensions. Virtual scrolling cannot calculate a viewport from an unsized element.

Overscan

overscan.ts
grid.updateOptions({
overscanRows: 14,
overscanCols: 6,
});

Higher overscan can reduce visible blanking during fast scrolls, but it increases rendered cell count.

Programmatic Scrolling

scroll-api.ts
grid.scroll.toCell(5000, 0);
const position = grid.scroll.getPosition();
const visibleRange = grid.scroll.getVisibleRange();
const tour = grid.scroll.throughCells(
[
{ row: 0, col: 0 },
{ row: 100, col: 2 },
{ row: 1000, col: 4 },
],
{ delayMs: 500, smooth: true }
);
await tour.promise;

Backend Windows

For very large datasets, combine virtual scrolling with backend data loading.

backend-virtual-grid.ts
const grid = new Grid(container, {
columns,
rowCount: 1_000_000,
colCount: columns.length,
rowHeight: 36,
colWidth: columns.map((column) => column.width ?? 140),
dataMode: 'backend',
onDataRequest: async (request) => fetchRows(request),
});

Tuning Checklist

  • Keep row renderers cheap.
  • Use stable row heights unless your app needs auto height.
  • Increase overscanRows only after checking actual devices.
  • Avoid synchronous work in scroll event handlers.
  • Prefer backend mode when the full row matrix is too large for memory.