React grid virtualization

React data grid virtualization for large tables

Virtualization is the difference between rendering a usable viewport and asking React to mount an entire dataset. Ace Grid treats virtualization as part of the grid surface, not a decorative performance toggle.

Open virtualization API Choose a data strategy

Understand the rendering model

Without virtualization, the browser may create DOM for every visible and offscreen row and cell. Style calculation, layout, paint, memory, and React reconciliation grow with that rendered surface. Row virtualization renders a moving vertical window; horizontal virtualization limits columns in wide grids; cell-content virtualization can defer expensive inner content. These techniques preserve a large logical dataset while keeping the mounted interface closer to the viewport.

Configure Ace Grid virtualization deliberately

Ace Grid exposes enableVirtualization, enableHorizontalVirtualization, and enableCellContentVirtualization through the virtual prop group. Start with row virtualization for tall datasets, add horizontal virtualization for many wide columns, and use content virtualization only when cell bodies are measurably expensive. Give the grid a bounded height and stable dimensions. Change one option at a time so performance improvements and interaction regressions can be attributed correctly.

Use stable row identity

Virtualized DOM is reused as the viewport moves, so record identity cannot depend on visual position. Every row needs a stable ID that survives sorting, filtering, loading, and updates. Test editing and selection while rapidly scrolling, then return to the same record and confirm state is attached to the row rather than the recycled element. Unstable IDs can produce edits, focus, or selection on the wrong business record.

Plan row height and overscan

Predictable row height makes scroll offsets and viewport calculations reliable. Variable heights require measurement and can cause jumps when content changes. Overscan renders a buffer beyond the visible area to avoid blank edges during fast movement, but excessive overscan recreates much of the DOM cost virtualization should remove. Test trackpad, mouse wheel, scrollbar drag, Page Down, keyboard navigation, and programmatic scrolling on target hardware.

Keep focus correct across recycled cells

A virtualized cell can leave the DOM while it remains logically selected or active. Define what happens when users scroll an edited cell away, move focus beyond the rendered window, or return to a selected row. Test pinned columns, pinned rows, custom controls, validation messages, and context menus. Performance is not acceptable if users lose keyboard position, commit an edit unexpectedly, or cannot return to the active record.

Separate virtualization from infinite loading

Virtualization controls rendering; infinite loading controls when additional rows are requested. Ace Grid scroll props support host-driven loading with batch size, threshold, direction, offset, page, or cursor strategies. The grid requests data, but the application updates the row source. Define duplicate prevention, cursor advancement, retry, end-of-data, and selection behavior across loaded windows. A fast viewport cannot compensate for an unreliable loading contract.

Know when to use a server row model

Use client virtualization when the browser can store and process the working set. Use infinite loading for sequential discovery where appending pages is sufficient. Evaluate Enterprise server row model when the server must own global filtering, sorting, grouping, pivoting, or paging. Server-backed grids require stable ordering, request cancellation, cache policy, total-row semantics, and authorization. These are data architecture decisions, not virtualization settings.

Benchmark a representative production grid

Record browser, device, row count, column count, row height, renderer complexity, dataset location, and enabled features. Measure time to usable interaction, fast-scroll blanking, edit-start delay, filter response, memory growth, and long tasks. Repeat the same scripted tasks before and after each change. Avoid publishing a universal row limit because performance depends on the complete rendering and data-processing workload.

Recognize common failure modes

Watch for changing row heights, unstable IDs, expensive renderers, synchronous formatting, oversized overscan, controlled state that updates every scroll event, and remote requests without cancellation. Also test loading placeholders, empty results, errors, stale responses, and rapid filter changes. Fix the dominant measured cost first. Enabling every virtualization option cannot repair slow queries, unnecessary React work, or custom cells that perform expensive computation during render.

Test pinned and grouped surfaces

Pinned rows, pinned columns, group headers, detail panels, and totals can follow different rendering paths from the central viewport. Verify alignment, focus movement, resizing, and scroll synchronization when these features are combined with virtualization. Test a wide grid with both vertical and horizontal movement because issues may appear only when the active cell crosses a pinned boundary or a virtualized column is remounted.

Optimize data transformations separately

Client sorting, filtering, grouping, aggregation, and formatting may dominate performance even when DOM rendering is bounded. Profile these operations independently. Avoid rebuilding columns or large row objects on every render, and debounce user-driven server queries where appropriate. If client transformations exceed the interaction budget, move the operation to a worker or server rather than increasing virtualization settings.

Define a performance budget

Set measurable thresholds for the target devices: time to first usable interaction, maximum edit-start delay, acceptable filter response, scroll blanking, long-task duration, and memory growth. Budgets make regressions visible in CI or release testing. Use representative data generators and custom renderers so tests remain repeatable. A performance claim without hardware, workload, and measurements is not useful evidence.

Live Ace Grid example

Virtualized viewport preview

Visible row windows, load states, render health, and scroll actions for large-grid evaluation.

Visible rowViewportLoad stateCellsRenderAction
Row 12,480VisibleLive98092%Render
Row 12,481VisibleLive87089%Scroll
Row 12,482PrefetchReview33073%Load
Row 12,483PendingEscalate21058%Fetch

Virtualized Ace Grid example

import { Grid } from "@ace-grid/core";

export function VirtualizedOrdersGrid({ rows, columns, loadMoreRows }) {
  return (
    <Grid
      data={{ rows, columns }}
      columns={{ columnWidths: {}, fillWidth: true }}
      layout={{ width: 1200, height: 600 }}
      virtual={{
        enableVirtualization: true,
        enableHorizontalVirtualization: true,
        enableCellContentVirtualization: true,
      }}
      scroll={{
        enableInfiniteScroll: true,
        infiniteScrollBatchSize: 100,
        loadMoreRows,
      }}
    />
  );
}

Rendering and data-loading strategies

Strategy What it solves What it does not solve
Row virtualization Bounds mounted row elements Does not reduce local data-processing cost
Horizontal virtualization Bounds cells in very wide grids Adds focus and measurement cases to test
Infinite loading Fetches additional rows near a scroll boundary Separate from viewport rendering
Server row model Moves sort, filter, grouping, and paging to a remote data source Requires Enterprise and a reliable request contract

Sources