Performance
@toolbox-web/grid is engineered for high performance out of the box. This guide helps you understand the performance characteristics and tune the grid for your specific workload.
Key Performance Features
Section titled “Key Performance Features”Row Virtualization
Section titled “Row Virtualization”The grid only renders rows visible in the viewport plus a configurable overscan buffer. This means rendering 100,000 rows is as fast as rendering 50 rows.
grid.gridConfig = { columns: [...], rowHeight: 28, // Fixed row height in pixels (default: auto-measured)};- Default row height: Auto-measured from first row (respects
--tbw-row-heightCSS variable) - Variable row heights: Supported via
rowHeight: (row, index) => number | undefined
Column Virtualization
Section titled “Column Virtualization”For grids with many columns (50+), enable column virtualization:
import '@toolbox-web/grid/features/column-virtualization';
grid.gridConfig = { columns: manyColumns, features: { columnVirtualization: true },};Render Scheduler
Section titled “Render Scheduler”All rendering is batched through a centralized RenderScheduler that coalesces multiple update requests into a single requestAnimationFrame callback.
Render phases (lowest → highest priority):
| Phase | Priority | What It Does |
|---|---|---|
| STYLE | 1 | CSS custom property updates |
| VIRTUALIZATION | 2 | Scroll position + visible window recalc |
| HEADER | 3 | Header row re-render |
| ROWS | 4 | Data row re-render |
| COLUMNS | 5 | Column structure rebuild |
| FULL | 6 | Complete re-render |
When multiple phases are requested in the same frame, only the highest-priority phase executes (it inherently covers lower phases).
Bundle Size Optimization
Section titled “Bundle Size Optimization”Tree-Shaking Features
Section titled “Tree-Shaking Features”The most important optimization: only import the features you use.
// ✅ Optimal: ~45 KB core + only features you needimport '@toolbox-web/grid';import '@toolbox-web/grid/features/selection';import '@toolbox-web/grid/features/editing';
// ❌ Heavy: imports ALL plugins even if you use twoimport '@toolbox-web/grid/all';Budget Reference
Section titled “Budget Reference”| Bundle | Raw | Gzipped |
|---|---|---|
Core (index.js) | ≤ 170 KB | ≤ 45 KB |
| Individual plugin | 2–15 KB | 1–5 KB |
All plugins (all.js) | ~300 KB | ~80 KB |
Tuning for Large Datasets
Section titled “Tuning for Large Datasets”Fixed Row Heights
Section titled “Fixed Row Heights”Variable row heights (rowHeight: (row) => number) require measuring each row, which is slower than fixed heights. For datasets over 10,000 rows, prefer fixed heights:
grid.gridConfig = { rowHeight: 32,};Disable Animations
Section titled “Disable Animations”Row animations add visual polish but cost CPU cycles. Disable them for very large datasets:
grid.gridConfig = { animation: false,};Batch Data Updates
Section titled “Batch Data Updates”When updating many rows, assign the entire array at once rather than using insertRow() / removeRow() in a loop:
// ✅ Single assignment — triggers one sort/filter/render cyclegrid.rows = updatedData;
// ❌ Loop — triggers N animations and N re-rendersfor (const newRow of newRows) { await grid.insertRow(0, newRow);}Debounce Filtering
Section titled “Debounce Filtering”When using filtering with a large dataset, increase the debounce to reduce re-filtering:
import '@toolbox-web/grid/features/filtering';
grid.gridConfig = { features: { filtering: { debounceMs: 300 } }, // Default: 200};Custom Sort Comparators
Section titled “Custom Sort Comparators”For fields with expensive comparisons, provide a pre-computed sort key:
{ field: 'name', sortable: true, comparator: (a: string, b: string) => a.localeCompare(b, undefined, { sensitivity: 'base' }),}Rendering Best Practices
Section titled “Rendering Best Practices”Avoid Direct DOM Manipulation
Section titled “Avoid Direct DOM Manipulation”Let the grid manage its DOM. Direct manipulation can conflict with the render scheduler and virtualization:
// ❌ Don't do this — bypasses the grid's render cycledocument.querySelector('.data-grid-row')!.style.background = 'red';
// ✅ Use rowClass/cellClass or a renderer insteadgrid.gridConfig = { rowClass: (row) => row.status === 'error' ? 'row-error' : '',};Use registerStyles() for Dynamic Runtime CSS
Section titled “Use registerStyles() for Dynamic Runtime CSS”Standard CSS (stylesheets, <style> in <head>) works fine for static styles. For styles you need to inject or toggle from JavaScript at runtime, use registerStyles() instead of appending <style> elements inside the grid (which get removed by replaceChildren()):
grid.registerStyles('my-highlights', ` .highlight-row { background: yellow; }`);
// Clean up when donegrid.unregisterStyles('my-highlights');Prefer Formatters Over Renderers
Section titled “Prefer Formatters Over Renderers”Formatters return a plain string — significantly faster than creating DOM elements via a renderer. Use a renderer only when you need interactive elements or custom HTML structure:
// ✅ Fast — formatter returns a string (no DOM creation){ field: 'salary', format: (v) => `$${v.toFixed(2)}` }
// ⚠️ Slower — renderer creates DOM elements (use only when needed){ field: 'status', renderer: (ctx) => { const badge = document.createElement('span'); badge.className = `badge-${ctx.value}`; badge.textContent = String(ctx.value); return badge;}}Profiling
Section titled “Profiling”Browser DevTools
Section titled “Browser DevTools”- Open Chrome DevTools → Performance tab
- Record while scrolling or sorting
- Look for long tasks (> 50ms) in the flame chart
- Check for layout thrashing (forced reflows)
Key Metrics to Watch
Section titled “Key Metrics to Watch”| Metric | Target | How to Measure |
|---|---|---|
| Scroll FPS | 60fps | Performance tab → Frames |
| Sort time (10K rows) | < 50ms | console.time() around grid.rows = sorted |
| Filter time (10K rows) | < 30ms | Measure in filter-change event handler |
| Initial render | < 100ms | Performance tab → First Paint |
| Memory (100K rows) | < 100 MB | Memory tab → Heap snapshot |
Stress Test
Section titled “Stress Test”Try the interactive stress test below — adjust row and column counts to see how the grid performs with large datasets:
Click Run Full Benchmark to test all grid operations.
Tests: Initial render, scroll performance, sort, filter, data update, selection, memory usage