Virtual Scrolling
Relevant source files
The following files were used as context for generating this wiki page:
Virtual Scrolling is a high-performance rendering technique designed to handle large datasets (up to millions of rows) efficiently within the Better Tables ecosystem. Instead of rendering every data row in the DOM, the system renders only the items currently visible in the viewport, plus a small buffer of "overscan" items to ensure smooth scrolling. Sources: README.md:237-239, packages/core/src/types/virtualization.ts:1-7.
This system is composed of a core VirtualizationManager that handles mathematical calculations and state, a set of React hooks for data integration, and specialized UI components for display. It supports both vertical and horizontal virtualization, dynamic row heights, and programmatic scrolling. Sources: packages/core/src/types/virtualization.ts:40-66, packages/core/tests/managers/virtualization-manager.test.ts:186-200.
Architecture and Components
The virtualization architecture follows a clear separation between calculation logic (Core) and rendering logic (UI).
Virtualization Lifecycle
The following diagram illustrates the flow from a scroll event to a re-rendered table view.
The system uses a VirtualizationManager to compute the startIndex and endIndex based on scrollTop and clientHeight. Sources: packages/core/tests/managers/virtualization-manager.test.ts:68-90, packages/core/src/types/virtualization.ts:200-220.
Core Components
- VirtualizationManager: A core class (tested extensively) that manages the logic for calculating virtual items. It handles row measurement caching, scroll updates, and performance metrics. Sources: packages/core/tests/managers/virtualization-manager.test.ts:11-30, packages/core/src/types/virtualization.ts:316-340.
- useVirtualization Hook: A React hook that stabilizes virtualization configurations and manages manager subscriptions, preventing unnecessary re-renders. Sources: plans/025-ui-render-performance.md:43-50.
- VirtualizedTable: The primary UI component that implements the
VirtualizedRowlogic and handles DOM-level scrolling containers. Sources: packages/ui/src/components/table/virtualized-table.tsx:296-326.
Data Structures
The system relies on specific interfaces to maintain type safety across the core and UI packages.
Configuration and State
| Interface | Description | Key Fields |
|---|---|---|
VirtualizationConfig | Parameters for the virtualization engine. | containerHeight, defaultRowHeight, overscan, dynamicRowHeight |
VirtualizationState | The current snapshot of the virtualized view. | virtualRows, startIndex, endIndex, totalHeight, enabled |
ScrollInfo | Raw DOM scroll metrics. | scrollTop, scrollLeft, clientHeight, scrollHeight |
Sources: packages/core/src/types/virtualization.ts:17-105, packages/core/src/types/virtualization.ts:184-228.
Item Mapping
Individual items are represented by VirtualRowItem and VirtualColumnItem, which provide precise pixel coordinates for absolute positioning within the scrollable area.
Performance Optimization
Virtual scrolling in Better Tables implements several advanced optimization strategies to maintain high frame rates.
1. Dynamic Row Height and Measurement
When dynamicRowHeight is enabled, the system uses a ResizeObserver to measure rows as they are rendered. These measurements are cached in RowMeasurement objects. Sources: packages/core/src/types/virtualization.ts:286-310, packages/core/tests/managers/virtualization-manager.test.ts:101-115.
The VirtualizationManager amortizes offset revalidation to avoid linear prefix recomputations (O(N) operations) on every lookup. In large datasets (e.g., 50,000 rows), this ensures that lookups remain near O(1) after the initial cache fill. Sources: packages/core/tests/managers/virtualization-manager.test.ts:320-350.
2. Rendering Stability
To prevent "effect churn" and unnecessary DOM mutations:
- Stable Observers:
ResizeObserverinstances are created once and maintained through parent re-renders using stableonMeasurecallbacks. Sources: plans/025-ui-render-performance.md:43-48. - Memoized Rows: The
VirtualizedRowis often memoized to ensure that a state change in one row does not trigger a re-render of the entire virtual list. Sources: plans/025-ui-render-performance.md:51-58. - Overscan: A configurable number of rows are rendered above and below the visible area to prevent blank spaces during rapid scrolling. Sources: packages/core/src/types/virtualization.ts:46-47, packages/core/tests/managers/virtualization-manager.test.ts:88-100.
3. Horizontal Virtualization
For tables with many columns, horizontal virtualization can be enabled via horizontalVirtualization: true. This applies the same "render-only-visible" logic to the X-axis, calculating startColumnIndex and endColumnIndex. Sources: packages/core/src/types/virtualization.ts:60-66, packages/core/tests/managers/virtualization-manager.test.ts:186-200.
Implementation Example
Programmatic scrolling allows developers to navigate to specific rows or columns with various alignment options.
// Example of programmatic scroll to a specific row
manager.scrollTo({
rowIndex: 50,
align: 'center',
behavior: 'smooth'
});
Sources: packages/core/src/types/virtualization.ts:241-269, packages/core/tests/managers/virtualization-manager.test.ts:153-170.
Conclusion
Virtual Scrolling is the backbone of Better Tables' ability to handle large-scale data. By combining a calculation-heavy core with a stable React rendering layer, it achieves high efficiency (often >99% for large datasets) while maintaining support for complex features like dynamic content and horizontal scaling. Sources: packages/core/tests/managers/virtualization-manager.test.ts:210-220, plans/025-ui-render-performance.md:1-15.