RevoGrid Performance and Virtualization
RevoGrid is designed to stay responsive with large datasets by rendering only what is needed. This guide explains the main performance-related props and when to use them.
Virtual rendering is the default
The grid renders:
- visible rows and columns
- a small buffer outside the viewport
- pinned regions in coordinated viewports
This is why large datasets stay fast as long as cell templates and event handlers stay lightweight.
In practice, performance problems usually come from custom application code, not from the base grid itself. The most common causes are:
- expensive cell templates
- rebuilding
columnstoo often - pushing too much logic into per-cell render functions
- forcing full rerenders when a targeted update would be enough
frameSize
frameSize defines how many extra rows and columns are rendered outside the visible area.
grid.frameSize = 1;Use a higher value if:
- users scroll very quickly
- custom cells are visually expensive to mount
- you want a slightly larger pre-render buffer
Use a lower value if:
- you want to minimize off-screen rendering
- your templates are already cheap
Starting point:
1is a good default for most apps- increase it gradually if you see visible blanking during very fast scrolls
disableVirtualX
disableVirtualX disables lazy rendering for columns.
grid.disableVirtualX = true;This can help when:
- the grid has only a small number of columns
- you prefer stable DOM for horizontally visible cells
- initial rendering is more important than horizontal virtualization
Do not enable it by default for wide grids.
Example:
grid.disableVirtualX = grid.columns.length < 10;disableVirtualY
disableVirtualY disables lazy rendering for rows.
grid.disableVirtualY = true;This is only appropriate when the row count is small enough that full vertical rendering is affordable.
Example:
grid.disableVirtualY = grid.source.length < 100;jobsBeforeRender
jobsBeforeRender lets you defer the first meaningful render until required async work is ready.
grid.jobsBeforeRender = [
fetch('/api/schema').then(r => r.json()),
fetch('/api/initial-grid-state').then(r => r.json()),
];Good use cases:
- schema or permissions that must load before columns are built
- plugin bootstrapping that would otherwise cause immediate double rendering
- initial app state that must exist before the first visible grid
Typical setup:
const schemaJob = fetch('/api/columns').then(r => r.json());
const settingsJob = fetch('/api/grid-settings').then(r => r.json());
grid.jobsBeforeRender = [schemaJob, settingsJob];Renderer performance tips
- keep
cellTemplatework small - avoid network requests from inside renderers
- avoid rebuilding large arrays or objects on every cell render
- prefer data precomputation before assigning
source
Bad pattern:
cellTemplate: () => {
const expensive = largeArray.filter(x => x.active);
return h('div', expensive.length);
}Better pattern:
const activeCount = largeArray.filter(x => x.active).length;
cellTemplate: () => h('div', activeCount)Update methods for smoother UX
When you need to update a specific visible cell, setDataAt is often cheaper than rebuilding the entire grid state from scratch.
See Programmatic Grid Control.
Performance checklist
- use plain values before custom templates
- keep row data normalized before it reaches the grid
- prefer
setDataAtfor targeted updates - use
getVisibleSource()when operations only need the currently visible rows - leave virtualization enabled unless the dataset is genuinely small