Core reference / Virtualization
Virtualization
Virtualization is always enabled in OmniGrid — no opt-in is required. The core engine renders only the rows and columns currently visible in the scroll window, plus a small overscan margin. Off-screen nodes are recycled and repositioned via transform: translateY, which keeps the DOM node count constant regardless of dataset size.
How it works
The virtualizer maintains a pool of DOM row nodes. On scroll it:
- Recomputes the viewport range (start row index, end row index, visible columns).
- Reuses pooled nodes, updating each node's
transformto the correct offset and binding new row data. - Leaves the DOM structure unchanged — no creation or destruction of nodes on the scroll hot path.
Because row height is fixed (see rowHeight in Grid options), the virtualizer can compute exact offsets without measuring individual rows — the fundamental assumption that makes window rendering O(1) per scroll frame rather than O(n).
Scroll decoupling
Scroll-only changes (scrollTop / scrollLeft) flow through an ephemeral path that does not notify the React store. This means scrolling never triggers a React re-render — the DOM pool handles it imperatively. React re-renders are reserved for structural changes only: data mutations, column updates, and dimension changes.
Pinned columns
Horizontally pinned columns (left / right) back onto their own DOM pool. Each pin pane is a sibling inside the single scroll container and uses position: sticky so it shares the container's native vertical scroll — no imperative scrollTop sync required. On the horizontal axis, the pane's offset is translated into local coordinates so pinned cells always stay in view.
Tuning
Two options let you widen the rendered window to reduce edge artefacts:
| Option | Default | Description |
|---|---|---|
| rowOverscan | 4 | Extra rows rendered above and below the visible viewport to prevent blank flashes during fast scroll. |
| columnOverscan | 0 | Extra columns rendered beyond the horizontal scroll window. |
Usage
const gridOptions = {
columns: colDefs,
data: rows,
getRowId: (row) => row.id,
// Overscan rows render extra content above and below the
// visible window to prevent blank flashes on fast scroll.
rowOverscan: 10,
columnOverscan: 2,
};