PageSourceSearch

https://rv-grid.com/assets/blog_high-performance-javascript-excel-data-grid.md.DLjtoDIJ.js

js rv-grid.com collected 2026-09-25 19:53:22 UTC 152,559 bytes, 322 lines download raw bytes

1import{n as e}from"./chunks/rolldown-runtime.hePW80VL.js";import{St as t,ct as n,it as r,nt as i,ot as a}from"./chunks/framework.CC4wkWh5.js";import"./chunks/assets.9Ly-vK68.js";import{t as o}from"./chunks/CommercialFaq.uxPujpCp.js";var s=JSON.parse(`{"title":"High-Performance JavaScript Excel Data Grid: Complete Guide","description":"Build a high-performance JavaScript Excel data grid with virtual scrolling, editing, copy and paste, formulas, validation, and server-side data.","frontmatter":{"title":"High-Performance JavaScript Excel Data Grid: Complete Guide","description":"Build a high-performance JavaScript Excel data grid with virtual scrolling, editing, copy and paste, formulas, validation, and server-side data.","outline":"deep","faq":{"heading":"Frequently asked questions","items":[{"q":"What is a JavaScript Excel data grid?","a":"It is a web data-grid component with familiar spreadsheet interactions such as <a href='/guide/editing'>cell editing</a>, keyboard navigation, range selection, <a href='/guide/clipboard'>copy and paste</a>, formulas, autofill, validation, and export. Unlike a full spreadsheet application, it keeps your database, API, permissions, and business workflow in control."},{"q":"How do you keep a JavaScript data grid fast with large datasets?","a":"Use <a href='/guide/performance'>row and column virtualization</a>, keep source and column references stable, avoid heavy work inside cell renderers, apply targeted updates, batch persistence, and move filtering, sorting, grouping, or paging to the server when the complete dataset should not live in the browser."},{"q":"Can RevoGrid display 100,000 rows?","a":"RevoGrid uses row and column virtualization and publishes a <a href='/benchmarks'>reproducible benchmark</a> with 100,000 rows and 100 columns. Real performance depends on the browser, machine, data model, cell renderers, editors, pinned regions, and surrounding application code. Test your actual workload before making a production decision."},{"q":"Does RevoGrid support Excel formulas and XLSX export?","a":"Yes. <a href='/pro/'>RevoGrid Pro</a> adds Excel-like formula evaluation, smart autofill, formatting, history, and <a href='/guide/data-grid-export-excel'>.xlsx export</a> on top of the virtualized RevoGrid Core. These modules are separate from Core so teams can include only the advanced spreadsheet behavior they need."},{"q":"Does RevoGrid work with React, Vue, Angular, Svelte, and plain JavaScript?","a":"Yes. RevoGrid uses a <a href='/guide/installation'>Web Component core</a> and provides integrations for <a href='/react-data-grid'>React</a>, <a href='/vue-data-grid'>Vue</a>, <a href='/angular-data-grid'>Angular</a>, <a href='/svelte-data-grid'>Svelte</a>, <a href='/guide/ts/'>TypeScript</a>, and <a href='/guide/'>plain JavaScript</a>."},{"q":"Is RevoGrid open source?","a":"<a href='/guide/licensing'>RevoGrid Core is MIT-licensed</a>. Advanced spreadsheet workflows, collaboration features, and Excel export are available through <a href='/pro/'>RevoGrid Pro</a>."}]},"date":"2026-08-26T00:00:00.000Z","author":"RevoGrid Team","category":"Data Grid","tags":["Data Grid","JavaScript","Excel","Performance","RevoGrid"],"image":"/blog/high-performance-javascript-excel-data-grid.png","imageAlt":"High-performance JavaScript Excel data grid built with RevoGrid","head":[["meta",{"name":"keywords","content":"high performance JavaScript Excel data grid, JavaScript Excel data grid, Excel-like data grid, JavaScript spreadsheet component, virtualized data grid, data grid for large datasets, editable JavaScript data grid, paste from Excel JavaScript, React Excel data grid, Vue Excel data grid, Angular Excel data grid, RevoGrid"}],["link",{"rel":"canonical","href":"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid"}],["meta",{"property":"og:title","content":"High-Performance JavaScript Excel Data Grid: Complete Guide"}],["meta",{"property":"og:description","content":"Build an Excel-like JavaScript data grid that stays responsive with large datasets, editing, clipboard workflows, formulas, validation, and remote data."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:url","content":"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid"}],["meta",{"property":"og:image","content":"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:title","content":"High-Performance JavaScript Excel Data Grid: Complete Guide"}],["meta",{"name":"twitter:description","content":"Build an Excel-like JavaScript data grid that remains responsive as datasets and product workflows grow."}],["meta",{"name":"twitter:image","content":"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid.png"}],["script",{"type":"application/ld+json"},"{\\n  \\"@context\\": \\"https://schema.org\\",\\n  \\"@type\\": \\"Article\\",\\n  \\"headline\\": \\"Build a High-Performance Excel-Like Data Grid in JavaScript\\",\\n  \\"description\\": \\"Build a high-performance JavaScript Excel data grid with virtual scrolling, editing, copy and paste, formulas, validation, and server-side data.\\",\\n  \\"image\\": \\"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid.png\\",\\n  \\"author\\": {\\n    \\"@type\\": \\"Organization\\",\\n    \\"name\\": \\"RevoGrid Team\\"\\n  },\\n  \\"publisher\\": {\\n    \\"@type\\": \\"Organization\\",\\n    \\"name\\": \\"RevoGrid\\",\\n    \\"url\\": \\"https://rv-grid.com/\\"\\n  },\\n  \\"mainEntityOfPage\\": {\\n    \\"@type\\": \\"WebPage\\",\\n    \\"@id\\": \\"https://rv-grid.com/blog/high-performance-javascript-excel-data-grid\\"\\n  },\\n  \\"datePublished\\": \\"2026-08-26\\",\\n  \\"dateModified\\": \\"2026-09-03\\"\\n}\\n"]]},"headers":[],"relativePath":"blog/high-performance-javascript-excel-data-grid.md","filePath":"blog/high-performance-javascript-excel-data-grid.md"}`),c=n({name:`blog/high-performance-javascript-excel-data-grid.md`,setup(e){return(e,n)=>(t(),i(`div`,null,[n[0]||=r(`<h1 id="Build-a-High-Performance-Excel-Like-Data-Grid-in-JavaScript" tabindex="-1">Build a High-Performance Excel-Like Data Grid in JavaScript <a class="header-anchor" href="#Build-a-High-Performance-Excel-Like-Data-Grid-in-JavaScript" aria-label="Permalink to “Build a High-Performance Excel-Like Data Grid in JavaScript”">​</a></h1><p><img src="/blog/high-performance-javascript-excel-data-grid.png" alt="High-performance JavaScript Excel data grid built with RevoGrid" width="1663" height="945"></p><p>A <strong><a href="/excel-data-grid">high-performance JavaScript Excel data grid</a></strong> should give users the interactions they already understand from Excel without turning your web application into a spreadsheet file editor.</p><p>Users should be able to <a href="/guide/editing">edit with the keyboard</a>
1, select ranges, <a href="/guide/clipboard">paste blocks from Excel</a>, <a href="/guide/filters">filter thousands of records</a>, and keep scrolling without the interface becoming sluggish. Your application should still own the database, permissions, validation, calculations, API calls, and product-specific workflow.</p><p>That combination is harder than rendering a table. It requires a grid architecture built for both <strong>spreadsheet-like interaction</strong> and <strong>large-data performance</strong>.</p><blockquote><p><strong>Quick answer:</strong> Use a <a href="/guide/performance">virtualized data grid</a> that renders only the visible rows and columns, keeps <a href="/guide/realtime-updates">data updates incremental</a>, and exposes <a href="/guide/editing">editing</a> and <a href="/guide/clipboard">clipboard events</a> to your application. Start with the <a href="/guide/licensing">MIT-licensed RevoGrid Core</a> for the performance and editing foundation, then add <a href="/pro/">RevoGrid Pro</a> when you need formulas, autofill, formatting, history, collaboration, or Excel export.</p></blockquote><p>This guide explains the architecture, provides a working JavaScript example with 100,000 rows, and shows how to add the Excel-like features that production applications actually need.</p><h2 id="What-is-a-JavaScript-Excel-data-grid-" tabindex="-1">What is a JavaScript Excel data grid? <a class="header-anchor" href="#What-is-a-JavaScript-Excel-data-grid-" aria-label="Permalink to “What is a JavaScript Excel data grid?”">​</a></h2><p>A JavaScript Excel data grid is an interactive table component that combines the structure of a data grid with familiar spreadsheet behavior.</p><p>A production grid typically combines <a href="/guide/performance">virtual scrolling</a>, <a href="/guide/editing">editing</a>, keyboard navigation, range selection, <a href="/guide/clipboard">copy and paste</a>, <a href="/guide/filters">filtering</a>, <a href="/guide/sorting">sorting</a>, <a href="/guide/row/pin">pinned rows</a>, <a href="/guide/column/pin">pinned columns</a>, and application-owned validation. Spreadsheet-heavy products can add <a href="/guide/cell/formula">formulas</a>, autofill, undo and redo, formatting, and <a href="/guide/data-grid-export-excel">Excel export</a>.</p><p>The important distinction is <strong>who owns the data and workflow</strong>.</p><p>In a spreadsheet application, the workbook is usually the product. Users control sheets, cell positions, formulas, and document structure.</p><p>In a product data grid, the application remains in control. A row may represent an invoice, customer, task, inventory item, or financial record. The grid is the interaction layer over application-owned data.</p><table tabindex="0"><thead><tr><th>Component</th><th>Best suited to</th><th>Main limitation</th></tr></thead><tbody><tr><td>HTML table</td><td>Small, mostly read-only datasets</td><td>No built-in virtualization, editing model, range selection, or spreadsheet workflow</td></tr><tr><td>Basic data grid</td><td>Sorting, filtering, and standard CRUD screens</td><td>May not provide deep keyboard, clipboard, formula, or workbook behavior</td></tr><tr><td>Full spreadsheet component</td><td>Workbook-like products where sheets and formulas are the primary model</td><td>Can be unnecessarily document-centric for an application backed by an API or database</td></tr><tr><td><strong>Excel-like data grid</strong></td><td>SaaS, operations, reporting, planning, and admin products that need spreadsheet fluency</td><td>Requires a deliberate boundary between grid state and application state</td></tr></tbody></table><p>For a product-focused implementation, see the <a href="/excel-data-grid">RevoGrid Excel Data Grid</a> overview.</p><h2 id="Render-millions-of-cells-with-virtualization" tabindex="-1">Render millions of cells with virtualization <a class="header-anchor" href="#Render-millions-of-cells-with-virtualization" aria-label="Permalink to “Render millions of cells with virtualization”">​</a></h2><p>Imagine a planning screen with 100,000 rows and 50 columns. That dataset contains five million logical cells.</p><p>Trying to create a DOM element for every cell would produce far more browser work than the user can see or interact with. It increases layout work, memory pressure, event overhead, and the cost of every update.</p><p>A high-performance grid uses <strong><a href="/guide/performance">virtualization</a></strong> instead:</p><ol><li>Keep the complete logical data model, or the currently loaded server window, in application memory.</li><li>Calculate which rows and columns intersect the viewport.</li><li>Render only those visible cells plus a small buffer.</li><li>Reuse and recombine the rendered view as the user scrolls.</li><li>Apply edits to targeted cells or rows instead of rebuilding the entire grid.</li></ol><p>This architecture separates the <strong>logical dataset size</strong> from the <strong>rendered DOM size</strong>. A grid may represent millions of logical cells while only mounting the cells required for the current viewport.</p><h2 id="Choose-the-features-your-application-needs" tabindex="-1">Choose the features your application needs <a class="header-anchor" href="#Choose-the-features-your-application-needs" aria-label="Permalink to “Choose the features your application needs”">​</a></h2><p>A long feature list is less useful than understanding which layer should own each responsibility.</p><table tabindex="0"><thead><tr><th>
1Capability</th><th>Why it matters</th><th>RevoGrid layer</th></tr></thead><tbody><tr><td><a href="/guide/performance">Row and column virtualization</a></td><td>Keeps rendering work tied to the viewport rather than total dataset size</td><td>MIT Core</td></tr><tr><td><a href="/guide/editing">Cell editing</a> and <a href="/guide/wcag">keyboard navigation</a></td><td>Supports fast data-entry workflows</td><td>MIT Core</td></tr><tr><td><a href="/guide/api/selectionFocus">Range selection</a> and <a href="/guide/clipboard">clipboard</a></td><td>Lets users move tabular data between the app and Excel</td><td>MIT Core</td></tr><tr><td><a href="/guide/sorting">Sorting</a> and <a href="/guide/filters">filtering</a></td><td>Makes large datasets explorable</td><td>MIT Core</td></tr><tr><td><a href="/guide/row/pin">Pinned rows</a> and <a href="/guide/column/pin">columns</a></td><td>Keeps identifiers and totals visible</td><td>MIT Core</td></tr><tr><td><a href="/guide/cell/renderer">Custom cells</a> and <a href="/guide/cell/editor">editors</a></td><td>Adapts the grid to product-specific data types</td><td>MIT Core</td></tr><tr><td><a href="/guide/events-guide">Edit and paste events</a></td><td>Connects validation, permissions, persistence, and analytics</td><td>MIT Core</td></tr><tr><td><a href="/guide/cell/formula">Formulas and formula tooling</a></td><td>Adds calculated spreadsheet-style workflows</td><td>Pro</td></tr><tr><td><a href="https://pro.rv-grid.com/guides/data-manage/autofill/" target="_blank" rel="noreferrer">Smart autofill and preview</a></td><td>Extends sequences and repeated values efficiently</td><td>Pro</td></tr><tr><td><a href="https://pro.rv-grid.com/guides/data-manage/history/" target="_blank" rel="noreferrer">Undo, redo, and audit workflows</a></td><td>Makes dense editing safer and reviewable</td><td>Pro</td></tr><tr><td><a href="https://pro.rv-grid.com/guides/data-grid/format-cells/" target="_blank" rel="noreferrer">Rich formatting and Excel-compatible clipboard</a></td><td>Preserves more spreadsheet context</td><td>Pro</td></tr><tr><td><a href="/guide/data-grid-export-excel">XLSX export</a> and CSV import</td><td>Connects browser workflows with workbook-based processes; applications parse <code>.xlsx</code> imports</td><td>Pro</td></tr><tr><td><a href="https://pro.rv-grid.com/guides/data-manage/collaborative-editing/" target="_blank" rel="noreferrer">Collaboration and presence</a></td><td>
1Supports shared operational workspaces</td><td>Pro</td></tr></tbody></table><p>The grid should not hide this boundary. A team that needs only fast rendering, editing, and clipboard behavior can stay on Core. A team building a spreadsheet-heavy product can add the advanced modules without replacing the underlying grid.</p><h2 id="Build-a-high-performance-JavaScript-data-grid" tabindex="-1">Build a high-performance JavaScript data grid <a class="header-anchor" href="#Build-a-high-performance-JavaScript-data-grid" aria-label="Permalink to “Build a high-performance JavaScript data grid”">​</a></h2><p>The following example creates an editable forecast grid with 100,000 rows. It uses plain JavaScript so the same architecture is visible before adding a <a href="/guide/react/">React</a>, <a href="/guide/vue3/">Vue</a>, <a href="/guide/angular/">Angular</a>, or <a href="/guide/svelte/">Svelte</a> wrapper.</p><h3 id="_1-Install-RevoGrid" tabindex="-1">1. Install RevoGrid <a class="header-anchor" href="#_1-Install-RevoGrid" aria-label="Permalink to “1. Install RevoGrid”">​</a></h3><div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">npm</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> install</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> @revolist/revogrid</span></span></code></pre></div><p>See the <a href="/guide/installation">installation guide</a> for pnpm, Yarn, Bun, CDN, and standalone-module options.</p><h3 id="_2-Add-the-grid-element" tabindex="-1">2. Add the grid element <a class="header-anchor" href="#_2-Add-the-grid-element" aria-label="Permalink to “2. Add the grid element”">​</a></h3><div class="language-html"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">html</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">div</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> class</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;forecast-workspace&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
2<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  &lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">revo-grid</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;forecast-grid&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">revo-grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
3<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">div</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
4<span class="line"></span>
5<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">style</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
6<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  .forecast-workspace</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
7<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">    min-width</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">0</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
8<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">    width</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100</span><span style="--shiki-dark:#E06C75;--shiki-light:#c62739;">%</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
9<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
10<span class="line"></span>
11<span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">  #forecast-grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
12<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">    display</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">block</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
13<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">    width</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100</span><span style="--shiki-dark:#E06C75;--shiki-light:#c62739;">%</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
14<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">    height</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">640</span><span style="--shiki-dark:#E06C75;--shiki-light:#c62739;">px</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
15<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
16<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">style</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
17<span class="line"></span>
18<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> type</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;module&quot;</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> src</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;/src/main.js&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span></code></pre></div><p>A fixed or flex-constrained height is important because the grid needs a viewport to virtualize.</p><h3 id="_3-Define-stable-columns-and-source-data" tabindex="-1">3. Define stable columns and source data <a class="header-anchor" href="#_3-Define-stable-columns-and-source-data" aria-label="Permalink to “3. Define stable columns and source data”">​</a></h3><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span>
18<pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#7F848E;--shiki-dark-font-style:italic;--shiki-light:#62687b;--shiki-light-font-style:inherit;">// src/main.js</span></span>
19<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">defineCustomElements</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/revogrid/loader&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
20<span class="line"></span>
21<span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">defineCustomElements</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">();</span></span>
22<span class="line"></span>
23<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> regions</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;EMEA&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;AMER&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;APAC&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span>
24<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> statuses</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Draft&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Reviewed&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Approved&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span>
25<span class="line"></span>
26<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> Array</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">from</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({ </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">length</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100_000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> }, (</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">_</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">index</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">=&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> ({</span></span>
27<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 1</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
28<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  region</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">regions</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">[</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> regions</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#005CC5;">length</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">],</span></span>
29<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  account</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`Account </span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">\${</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">String</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 1</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">).</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">padStart</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">6</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">, </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;0&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">)</span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">}</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
30<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  units</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">10</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 500</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">),</span></span>
31<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  unitPrice</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">20</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 80</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">),</span></span>
32<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  status</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">statuses</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">[</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> statuses</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#005CC5;">length</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">],</span></span>
33<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}));
33</span></span>
34<span class="line"></span>
35<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> columns</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span></span>
36<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
37<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;id&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
38<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;ID&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
39<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">90</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
40<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    readonly</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
41<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    pin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;colPinStart&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
42<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
43<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
44<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;region&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
45<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Region&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
46<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">120</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
47<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    sortable</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
48<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
49<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
50<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;account&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
51<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Account&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
52<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">220</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
53<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    sortable</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
54<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
55<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
56<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;units&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
57<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Units&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
58<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">110</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
59<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
60<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
61<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;unitPrice&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
62<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Unit price&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
63<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">130</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
64<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
65<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
66<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;status&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
67<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Status&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
68<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">130</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
69<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
70<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span>
71<span class="line"></span>
72<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> grid</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> document</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">querySelector</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;#forecast-grid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
73<span class="line"></span>
74<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">!</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
75<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  throw</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> new</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> Error</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Forecast grid element was not found.&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
76<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span>
77<span class="line"></span>
78<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">Object</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">assign</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, {</span></span>
79<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
80<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  source</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
81<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  rowHeaders</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
82<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  range</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
83<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  filter</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
84<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  resize</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
85<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  frameSize</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">1</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
86<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  theme</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;compact&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
87<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  useClipboard</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: {</span></span>
88<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    rangeFill</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
89<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
90<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">});
90</span></span></code></pre></div><p>This gives the page:</p><ul><li><a href="/guide/performance">virtualized rows and columns</a></li><li>an <a href="/guide/editing">editable cell model</a></li><li><a href="/guide/wcag">keyboard navigation</a></li><li><a href="/guide/api/selectionFocus">range selection</a></li><li><a href="/guide/sorting">sorting</a> and <a href="/guide/filters">filtering</a></li><li>a <a href="/guide/column/pin">pinned identifier column</a></li><li><a href="/guide/clipboard">copy and paste</a> compatible with tabular spreadsheet data</li><li>spreadsheet-style fill when one copied value is pasted into a selected range</li></ul><p>The arrays are created once and assigned once. That stability matters: recreating <code>columns</code> or replacing the full <code>source</code> after every cell edit can erase much of the benefit of an optimized grid.</p><h2 id="Validate-and-persist-edits" tabindex="-1">Validate and persist edits <a class="header-anchor" href="#Validate-and-persist-edits" aria-label="Permalink to “Validate and persist edits”">​</a></h2><p>An editable data grid becomes part of the application only when edits flow through product rules.</p><p>Use <a href="/guide/editing#editing-lifecycle-events"><code>beforeedit</code> and <code>afteredit</code></a> to connect the grid to application validation and persistence. <code>beforeedit</code> can reject or normalize a value before it is committed; <code>afteredit</code> receives the accepted change after Core applies it.</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> pendingChanges</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [];</span></span>
91<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">let</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;"> flushTimer</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 0</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
92<span class="line"></span>
93<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">function</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> isInvalidNumber</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
94<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  return</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> ===</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;units&#39;</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> ||</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;"> prop</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> ===</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;unitPrice&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) </span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">&amp;&amp;</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> Number</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) </span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">&lt;</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 0</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
95<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span>
96<span class="line"></span>
97<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">addEventListener</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;beforeedit&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">event</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> =&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
98<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">=</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
99<span class="line"></span>
100<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">isInvalidNumber</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)) {</span></span>
101<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">preventDefault</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">();</span></span>
102<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    return</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
103<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
104<span class="line"></span>
105<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> ===</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;account&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
106<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> String</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">).</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">trim</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">();</span></span>
107<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
108<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">});
108</span></span>
109<span class="line"></span>
110<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">addEventListener</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;beforerangeedit&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">event</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> =&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
111<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> containsInvalidValue</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> Object</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">values</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">data</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">).</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">some</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">values</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> =&gt;</span></span>
112<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    Object</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">entries</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">values</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">).</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">some</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(([</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">]) </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">=&gt;</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> isInvalidNumber</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)),</span></span>
113<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  );</span></span>
114<span class="line"></span>
115<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">containsInvalidValue</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
116<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">preventDefault</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">();</span></span>
117<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
118<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">});
118</span></span>
119<span class="line"></span>
120<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">addEventListener</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;afteredit&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">event</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> =&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
121<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> detail</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> event</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
122<span class="line"></span>
123<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;data&#39;</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> in</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;"> detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
124<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    for</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">rowIndex</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">values</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">] </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">of</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> Object</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">entries</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">data</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)) {</span></span>
125<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">      const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> model</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">models</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">[</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">Number</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">rowIndex</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)];</span></span>
126<span class="line"></span>
127<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">      if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">!</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">model</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
128<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">        continue</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
129<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">      }</span></span>
130<span class="line"></span>
131<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">      for</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">field</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">value</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">] </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">of</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> Object</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">entries</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">values</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)) {</span></span>
132<span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">        queueChange</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({ </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">model</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">field</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">value</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> });</span></span>
133<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">      }</span></span>
134<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    }</span></span>
135<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    return</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
136<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
137<span class="line"></span>
138<span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">  queueChange</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">
138({</span></span>
139<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">model</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
140<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    field</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
141<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    value</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
142<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  });</span></span>
143<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">});</span></span>
144<span class="line"></span>
145<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">function</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> queueChange</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">change</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
146<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">  pendingChanges</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">push</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">change</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
147<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">  window</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">clearTimeout</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">flushTimer</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
148<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  flushTimer</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> window</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">setTimeout</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">flushChanges</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">250</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
149<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span>
150<span class="line"></span>
151<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">async</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> function</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> flushChanges</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">() {</span></span>
152<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> changes</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> pendingChanges</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">splice</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">0</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
153<span class="line"></span>
154<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">!</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">changes</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#005CC5;">length</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
155<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    return</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
156<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
157<span class="line"></span>
158<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  try</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
159<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> response</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> await</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> fetch</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;/api/forecast/batch&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, {</span></span>
160<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">      method</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;PATCH&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
161<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">      headers</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: {</span></span>
162<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">        &#39;Content-Type&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;application/json&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
163<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">      },</span></span>
164<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">      body</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">JSON</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">stringify</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({ </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">changes</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> }),</span></span>
165<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    });</span></span>
166<span class="line"></span>
167<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">    if</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">!</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">response</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">ok</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
168<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">      throw</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> new</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> Error</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`Save failed with status </span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">\${</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">response</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">status</span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">}</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
169<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    }</span></span>
170<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">catch</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">error</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
171<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    pendingChanges</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">unshift</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#c62739;">...</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">changes</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
172<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    console</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">error</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Could not save forecast changes:&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">error</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
173<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }</span></span>
174<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span></code></pre></div><p><code>afteredit</code> reports single-cell edits as <code>{ model, prop, val }</code> and range edits as row-indexed <code>data</code> and <code>models</code> maps. Handling both shapes lets paste and autofill share the same persistence queue. Batching then prevents a spreadsheet-like interaction from producing one network request per changed cell.</p><p>A production implementation should also define retry, conflict, rollback, and user-notification behavior. The grid provides the events; the application owns the business decision.</p><h2 id="Copy-and-paste-between-Excel-and-the-browser" tabindex="-1">Copy and paste between Excel and the browser <a class="header-anchor" href="#Copy-and-paste-between-Excel-and-the-browser" aria-label="Permalink to “Copy and paste between Excel and the browser”">​</a></h2><p>Clipboard behavior is one of the most important differences between a table and an Excel-like data grid.</p><p>
174RevoGrid Core can copy selected cells as tab-separated rows, which makes the data compatible with Excel and other spreadsheet applications. When users paste, the grid applies the clipboard matrix starting from the focused cell.</p><p>Enable range selection for block operations:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">range</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span></code></pre></div><p>Enable one-value-to-range fill behavior:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">useClipboard</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
175<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  rangeFill</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
176<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">};</span></span></code></pre></div><p>The <a href="/guide/clipboard#handling-clipboard-events">clipboard lifecycle</a> is observable. You can use events such as <code>beforepaste</code>, <code>beforepasteapply</code>, and <code>afterpasteapply</code> to reject a paste, transform values, enforce permissions, or trigger persistence after the range is applied.</p><p>For workflows where pasted rows should extend the current dataset, Core also provides <code>AutoAddRowsPlugin</code>:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">AutoAddRowsPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/revogrid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
177<span class="line"></span>
178<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">plugins</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">AutoAddRowsPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">]; </span><span style="--shiki-dark:#7F848E;--shiki-dark-font-style:italic;--shiki-light:#62687b;--shiki-light-font-style:inherit;">// Include alongside any other plugins.</span></span></code></pre></div><p>Applications still own column definitions. Automatically inventing new columns from pasted data would bypass the types, editors, validation rules, permissions, and formatting associated with each application field.</p><p>Read the complete <a href="/guide/clipboard">
178clipboard operations guide</a> for copy, paste, cut, range fill, and paste-event patterns.</p><h2 id="Add-formulas-autofill-history-formatting-and-Excel-export" tabindex="-1">Add formulas, autofill, history, formatting, and Excel export <a class="header-anchor" href="#Add-formulas-autofill-history-formatting-and-Excel-export" aria-label="Permalink to “Add formulas, autofill, history, formatting, and Excel export”">​</a></h2><p>The previous example uses the <a href="/guide/licensing">MIT-licensed Core</a>. Spreadsheet-heavy applications can add focused <a href="/pro/">RevoGrid Pro modules</a> without replacing the grid.</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/revogrid-pro/dist/revogrid-pro.css&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
179<span class="line"></span>
180<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
181<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  AutoFillPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
182<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  AutoFillPreviewPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
183<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  DataGridFormattingPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
184<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  EventManagerPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
185<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  ExportExcelPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
186<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  FormulaPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
187<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  HistoryPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
188<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">} </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/revogrid-pro&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
189<span class="line"></span>
190<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">eventManager</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
191<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  applyEventsToSource</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
192<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">};</span></span>
193<span class="line"></span>
194<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">plugins</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span></span>
195<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  EventManagerPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
196<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  FormulaPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
197<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  AutoFillPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
198<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  AutoFillPreviewPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
199<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  HistoryPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
200<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  DataGridFormattingPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
201<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  ExportExcelPlugin</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
202<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span></code></pre></div><p>You can then provide formula values inside the data model:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span>
202<pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span></span>
203<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;quantity&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Quantity&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
204<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;unitPrice&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Unit price&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
205<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;total&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Total&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">readonly</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
206<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span>
207<span class="line"></span>
208<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span></span>
209<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
210<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    quantity</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">12</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
211<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    unitPrice</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">19.5</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
212<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    total</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;=A1*B1&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
213<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
214<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  {</span></span>
215<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    quantity</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">8</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
216<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    unitPrice</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">27</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
217<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    total</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;=A2*B2&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
218<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  },</span></span>
219<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span></code></pre></div><p>Trigger an <code>.xlsx</code> export from an application button:</p><div class="language-html"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">html</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">button</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;export-forecast&quot;</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> type</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;button&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;Export forecast&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">button</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span></code></pre></div><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span>
219<pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">document</span></span>
220<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  .</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">querySelector</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;#export-forecast&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">)</span></span>
221<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  ?.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">addEventListener</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;click&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, () </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">=&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
222<span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">    grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">dispatchEvent</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span></span>
223<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">      new</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> CustomEvent</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;export-excel&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, {</span></span>
224<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">        detail</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: {</span></span>
225<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">          workbookName</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;forecast.xlsx&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
226<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">          sheetName</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Forecast&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
227<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">        },</span></span>
228<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">      }),</span></span>
229<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    );</span></span>
230<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  });</span></span></code></pre></div><p>The modules solve different problems:</p><ul><li><a href="/guide/cell/formula"><code>FormulaPlugin</code></a> evaluates Excel-like formulas.</li><li><a href="https://pro.rv-grid.com/guides/data-manage/autofill/" target="_blank" rel="noreferrer"><code>AutoFillPlugin</code></a> extends values and sequences.</li><li><a href="https://pro.rv-grid.com/guides/data-manage/autofill/" target="_blank" rel="noreferrer"><code>AutoFillPreviewPlugin</code></a> shows the predicted result before users commit a fill.</li><li><a href="https://pro.rv-grid.com/guides/data-manage/history/" target="_blank" rel="noreferrer"><code>HistoryPlugin</code></a> adds undo and redo infrastructure.</li><li><a href="https://pro.rv-grid.com/guides/data-grid/format-cells/" target="_blank" rel="noreferrer"><code>DataGridFormattingPlugin</code></a> supports richer spreadsheet formatting and clipboard workflows.</li><li><a href="/guide/data-grid-export-excel"><code>ExportExcelPlugin</code></a> prepares and exports workbook data.</li></ul><p><code>ExportExcelPlugin</code> imports CSV files and exports <code>.xlsx</code> workbooks. Importing an existing <code>.xlsx</code> or <code>.xls</code> workbook remains application-owned: parse it with your chosen workbook library, map the result to row objects, and assign the normalized rows to <code>source</code>.</p><p>This modular model avoids forcing every application to carry spreadsheet behavior it does not use.</p><p>Explore the complete <a href="https://pro.rv-grid.com/guides/" target="_blank" rel="noreferrer">RevoGrid Pro documentation</a> or start with the <a href="/trial">30-day Pro trial</a>.</p><h2 id="Keep-large-datasets-responsive" tabindex="-1">Keep large datasets responsive <a class="header-anchor" href="#Keep-large-datasets-responsive" aria-label="Permalink to “Keep large datasets responsive”">​</a></h2><p>Virtualization is necessary, but it is not sufficient. A poorly designed application can make a fast grid slow by putting expensive work around it.</p><h3 id="Keep-virtualization-enabled" tabindex="-1">Keep virtualization enabled <a class="header-anchor" href="#Keep-virtualization-enabled" aria-label="Permalink to “Keep virtualization enabled”">​</a></h3><p>RevoGrid virtualizes rows and columns by default. Disable vertical or horizontal virtualization only when the corresponding dimension is genuinely small and stable.</p><p>The <code>frameSize</code> property controls the off-screen buffer:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span>
230<pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;">grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">frameSize</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 1</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span></code></pre></div><p>A value of <code>1</code> is a practical starting point. Increase it gradually if very fast scrolling exposes temporary blanking with expensive custom cells. Lower values reduce off-screen rendering.</p><h3 id="Keep-source-and-columns-stable" tabindex="-1">Keep <code>source</code> and <code>columns</code> stable <a class="header-anchor" href="#Keep-source-and-columns-stable" aria-label="Permalink to “Keep source and columns stable”">​</a></h3><p>Treat full <code>source</code> replacement as loading a new dataset, not as the default response to a cell edit. Apply an incremental grid change and sync a patch or batch instead. Replace the complete source only when the dataset changes, such as after a page switch, server refresh, filter result, or externally authored row insertion or removal.</p><h3 id="Use-targeted-updates" tabindex="-1">Use targeted updates <a class="header-anchor" href="#Use-targeted-updates" aria-label="Permalink to “Use targeted updates”">​</a></h3><p>When application code needs to change one cell, use the <a href="/guide/programmatic-control#update-one-cell-with-setdataat"><code>setDataAt</code> targeted update method</a> rather than rebuilding the dataset:</p><div class="language-js"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">await</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> grid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">setDataAt</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({</span></span>
231<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  row</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">12</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
232<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  col</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">4</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
233<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  val</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">98.5</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
234<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">});</span></span></code></pre></div><p>Targeted updates are particularly valuable for live prices, operational statuses, progress values, validation results, and collaborative changes.</p><h3 id="Keep-cell-renderers-inexpensive" tabindex="-1">Keep cell renderers inexpensive <a class="header-anchor" href="#Keep-cell-renderers-inexpensive" aria-label="Permalink to “Keep cell renderers inexpensive”">​</a></h3><p>A custom cell renderer may execute many times while the viewport changes. Avoid:</p><ul><li>network requests inside cell rendering</li><li>filtering or sorting large arrays per cell</li><li>repeatedly creating heavy framework component trees</li><li>unnecessary images, charts, or layout measurements in every visible cell</li><li>formatting work that could be precomputed once</li></ul><p>A virtualized grid limits how many cells exist, but expensive visible cells are still expensive.</p><h3 id="Batch-application-work" tabindex="-1">Batch application work <a class="header-anchor" href="#Batch-application-work" aria-label="Permalink to “Batch application work”">​</a></h3><p>A user can edit one cell, paste 500 cells, or fill 10,000 cells. Your persistence and analytics layers should be able to process transactions or batches rather than assuming every action changes exactly one value.</p><h3 id="Measure-your-real-workload" tabindex="-1">Measure your real workload <a class="header-anchor" href="#Measure-your-real-workload" aria-label="Permalink to “Measure your real workload”">​</a></h3><p>A benchmark with plain text cells does not predict a grid filled with dropdowns, charts, validators, conditional styles, and framework components. Test the same row count, column count, renderers, pinned regions, editors, and update patterns used by your product.</p><p>See the <a href="/guide/performance">
234RevoGrid performance and virtualization guide</a> for the full checklist.</p><h2 id="Verify-performance-with-the-100-000-row-benchmark" tabindex="-1">Verify performance with the 100,000-row benchmark <a class="header-anchor" href="#Verify-performance-with-the-100-000-row-benchmark" aria-label="Permalink to “Verify performance with the 100,000-row benchmark”">​</a></h2><p>RevoGrid publishes a reproducible local benchmark using <strong>100,000 rows and 100 columns</strong>, or <strong>10 million logical cells</strong>. The run was recorded on July 5, 2026 against a documented browser, machine, dataset, and renderer configuration.</p><table tabindex="0"><thead><tr><th>Metric</th><th style="text-align:right;">Published result</th></tr></thead><tbody><tr><td>Logical dataset</td><td style="text-align:right;">100,000 rows × 100 columns</td></tr><tr><td>Total logical cells</td><td style="text-align:right;">10,000,000</td></tr><tr><td>Initial render</td><td style="text-align:right;">34.10 ms</td></tr><tr><td>Scrolling</td><td style="text-align:right;">60 FPS normalized to a 60 Hz target</td></tr><tr><td>Dropped frames in scripted pass</td><td style="text-align:right;">2</td></tr><tr><td>Rendered viewport rows after warmup</td><td style="text-align:right;">60</td></tr><tr><td>Rendered data cells after warmup</td><td style="text-align:right;">260</td></tr><tr><td>DOM nodes in the benchmark document</td><td style="text-align:right;">807</td></tr><tr><td>Targeted edit latency, p95</td><td style="text-align:right;">0.10 ms</td></tr><tr><td>Heap after warmup</td><td style="text-align:right;">445.84 MiB median</td></tr><tr><td>Heap after interaction loop</td><td style="text-align:right;">482.06 MiB median</td></tr></tbody></table><p><img src="/benchmarks/revo-grid-benchmark.png" alt="RevoGrid benchmark with 100,000 rows and 100 columns" width="1440" height="900"></p><p>These numbers are <strong>not a universal guarantee</strong>. Data generation was excluded from the initial-render metric, and results vary with hardware, browser, refresh rate, cell complexity, application code, and measurement method.</p><p>The useful part is not a single headline number. It is the documented relationship between 10 million logical cells and a much smaller rendered viewport. Review the complete methodology, raw results, screenshot, and video on the <a href="/benchmarks">RevoGrid benchmark page</a>.</p><h2 id="Choose-local-or-server-side-data" tabindex="-1">Choose local or server-side data <a class="header-anchor" href="#Choose-local-or-server-side-data" aria-label="Permalink to “Choose local or server-side data”">​</a></h2><p>Virtualization answers a rendering question: how many cells should exist in the DOM?</p><p>It does not answer a data-architecture question: how much data should the browser download and own?</p><p>Keeping 100,000 rows in the browser can be appropriate when:</p><ul><li>the payload is compact</li><li>users need instant local exploration</li><li>client-side filtering and sorting are valuable</li><li>the machine and memory budget are known</li><li>the data is already available locally</li></ul><p>Server-side data is usually better when:</p><ul><li>the dataset contains millions of records</li><li>rows are permission-sensitive</li><li>queries require database indexes or aggregations</li><li>the data changes continuously on the server</li><li>loading the full payload delays the first useful screen</li><li>mobile or low-memory devices matter</li></ul><p>Use <a href="/guide/server-side-data#pagination-and-infinite-scrolling">server paging</a> when users think in stable pages. Use <a href="/guide/server-side-data#pagination-and-infinite-scrolling">infinite loading</a> when scrolling through a continuous result set is more natural. Send <a href="/guide/server-side-data#remote-filtering">filter</a> and <a href="/guide/server-side-data#remote-sorting">sort state</a> to the server when the operation must apply to records that are not currently loaded.</p><p>Read <a href="/guide/server-side-data">server-side data guidance</a> and <a href="/guide/data-sync">data loading and synchronization patterns</a> before choosing the ownership model.</p><h2 id="Use-RevoGrid-with-React-Vue-Angular-or-Svelte" tabindex="-1">Use RevoGrid with React, Vue, Angular, or Svelte <a class="header-anchor" href="#Use-RevoGrid-with-React-Vue-Angular-or-Svelte" aria-label="Permalink to “Use RevoGrid with React, Vue, Angular, or Svelte”">​</a></h2><p>RevoGrid&#39;s core is a <a href="/guide/installation">Web Component</a>. Its <a href="/react-data-grid">React</a>, <a href="/vue-data-grid">Vue</a>, <a href="/angular-data-grid">Angular</a>, and <a href="/svelte-data-grid">Svelte</a>
234 wrappers expose the same grid engine through each ecosystem&#39;s component model.</p><p>Move the stable columns and row generator into a shared module:</p><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">export</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> columns</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span></span>
235<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;id&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;ID&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">readonly</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">90</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
236<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;account&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Account&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">220</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
237<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;amount&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Amount&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">130</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
238<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">prop</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;status&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">name</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;Status&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">size</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">130</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> },</span></span>
239<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">];</span></span>
240<span class="line"></span>
241<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">export</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> function</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">count</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#c62739;">:</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> number</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) {</span></span>
242<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  return</span><span style="--shiki-dark:#E5C07B;--shiki-light:#24292E;"> Array</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">.</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">from</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({ </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">length</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">count</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> }, (</span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">_</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-dark-font-style:italic;--shiki-light:#c13617;--shiki-light-font-style:inherit;">index</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">) </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">=&gt;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> ({</span></span>
243<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    id</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 1</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
244<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    account</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`Account </span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">\${</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 1</span><span style="--shiki-dark:#C678DD;--shiki-light:#032F62;">}</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
245<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    amount</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">1000</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> +</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 5000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">),</span></span>
246<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">    status</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">index</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> %</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;"> 2</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> ?</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;Open&#39;</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> :</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;Reviewed&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
247<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  }));</span></span>
248<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span></code></pre></div><p>Install the wrapper for your framework:</p><div class="vp-code-group"><div class="tabs">
248<input type="radio" name="group-791" id="tab-792" checked><label data-title="React" for="tab-792">React</label><input type="radio" name="group-791" id="tab-793"><label data-title="Vue 3" for="tab-793">Vue 3</label><input type="radio" name="group-791" id="tab-794"><label data-title="Angular" for="tab-794">Angular</label><input type="radio" name="group-791" id="tab-795"><label data-title="Svelte" for="tab-795">Svelte</label></div><div class="blocks"><div class="language-bash active"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">npm</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> install</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> @revolist/react-datagrid</span></span></code></pre></div><div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">npm</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> install</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> @revolist/vue3-datagrid</span></span></code></pre></div><div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">npm</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> install</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> @revolist/angular-datagrid</span></span></code></pre></div><div class="language-bash"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">npm</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> install</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> @revolist/svelte-datagrid</span></span></code></pre></div></div></div><p>Then bind the same columns and source through the wrapper. Each example creates the large array only once instead of rebuilding it during a framework render cycle.</p><div class="vp-code-group"><div class="tabs"><input type="radio" name="group-800" id="tab-801" checked><label data-title="React" for="tab-801">React</label><input type="radio" name="group-800" id="tab-802"><label data-title="Vue 3" for="tab-802">Vue 3</label><input type="radio" name="group-800" id="tab-803"><label data-title="Angular" for="tab-803">Angular</label><input type="radio" name="group-800" id="tab-804"><label data-title="Svelte" for="tab-804">Svelte</label></div><div class="blocks"><div class="language-tsx active"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">tsx</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">useState</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;react&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
249<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">
249import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">RevoGrid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/react-datagrid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
250<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;./forecast-data&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
251<span class="line"></span>
252<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">export</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> default</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> function</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> ForecastGrid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">() {</span></span>
253<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> [</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">source</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">] </span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">=</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> useState</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(() </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">=&gt;</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100_000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">));</span></span>
254<span class="line"></span>
255<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  return</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> (</span></span>
256<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    &lt;</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">RevoGrid</span></span>
257<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      style</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">=</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">{</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">{ </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">height</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">640</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> }</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">}</span></span>
258<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      columns</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">=</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">{</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">}</span></span>
259<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;">=</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">
259{</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">source</span><span style="--shiki-dark:#C678DD;--shiki-light:#24292E;">}</span></span>
260<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      rowHeaders</span></span>
261<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      range</span></span>
262<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      filter</span></span>
263<span class="line"><span style="--shiki-dark:#D19A66;--shiki-dark-font-style:italic;--shiki-light:#6F42C1;--shiki-light-font-style:inherit;">      resize</span></span>
264<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    /&gt;</span></span>
265<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  );</span></span>
266<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span></code></pre></div><div class="language-vue"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">vue</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> setup</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> lang</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;ts&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
267<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">shallowRef</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;vue&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
268<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;"> RevoGrid</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/vue3-datagrid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
269<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;./forecast-data&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
270<span class="line"></span>
271<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> shallowRef</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100_000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">));</span></span>
272<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
273<span class="line"></span>
274<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">template</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
275<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  &lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">RevoGrid</span></span>
276<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">    style</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#005CC5;">height</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">640</span><span style="--shiki-dark:#E06C75;--shiki-light:#c62739;">px</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span></span>
277<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    :</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span></span>
278<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">    :</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">source</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">source</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#032F62;">&quot;</span></span>
279<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">    row-headers</span></span>
280<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">    range</span></span>
281<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">    filter</span></span>
282<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">    resize</span></span>
283<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">  /&gt;</span></span>
284<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">template</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span></code></pre></div><div class="language-ts"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">ts</span>
284<pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">Component</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@angular/core&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
285<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">RevoGrid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/angular-datagrid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
286<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;./forecast-data&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
287<span class="line"></span>
288<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">@</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;">Component</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">({</span></span>
289<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  selector</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&#39;app-forecast-grid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
290<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  standalone</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">true</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
291<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  imports</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: [</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">RevoGrid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">],</span></span>
292<span class="line"><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">  template</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">: </span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">\`</span></span>
293<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">    &lt;revo-grid</span></span>
294<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      style=&quot;height: 640px&quot;</span></span>
295<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [columns]=&quot;columns&quot;</span></span>
296<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [source]=&quot;source&quot;</span></span>
297<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [rowHeaders]=&quot;true&quot;</span></span>
298<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [range]=&quot;true&quot;</span></span>
299<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [filter]=&quot;true&quot;</span></span>
300<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">      [resize]=&quot;true&quot;</span></span>
301<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">    &gt;&lt;/revo-grid&gt;</span></span>
302<span class="line"><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">  \`</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">,</span></span>
303<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">})</span></span>
304<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">export</span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;"> class</span><span style="--shiki-dark:#E5C07B;--shiki-light:#6F42C1;"> ForecastGridComponent</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> {</span></span>
305<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  readonly</span><span style="--shiki-dark:#E06C75;--shiki-light:#c13617;"> columns</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;"> columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
306<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  readonly</span><span style="--shiki-dark:#E06C75;--shiki-light:#c13617;"> source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100_000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
307<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">}</span></span></code></pre></div><div class="language-svelte"><button title="Copy code" data-copied="Copied" class="copy"></button><span class="lang">svelte</span><pre class="shiki shiki-themes one-dark-pro github-light" style="--shiki-dark:#abb2bf;--shiki-light:#24292e;--shiki-dark-bg:#282c34;--shiki-light-bg:#fff;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;"> lang</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;ts&quot;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
308<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">
308  import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">RevoGrid</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;@revolist/svelte-datagrid&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
309<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  import</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> { </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">, </span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;"> } </span><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">from</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;"> &#39;./forecast-data&#39;</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">;</span></span>
310<span class="line"></span>
311<span class="line"><span style="--shiki-dark:#C678DD;--shiki-light:#c62739;">  const</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;"> source</span><span style="--shiki-dark:#56B6C2;--shiki-light:#c62739;"> =</span><span style="--shiki-dark:#61AFEF;--shiki-light:#6F42C1;"> createRows</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">(</span><span style="--shiki-dark:#D19A66;--shiki-light:#005CC5;">100_000</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">);</span></span>
312<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;/</span><span style="--shiki-dark:#E06C75;--shiki-light:#11782a;">script</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&gt;</span></span>
313<span class="line"></span>
314<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">&lt;</span><span style="--shiki-dark:#E5C07B;--shiki-light:#005CC5;">RevoGrid</span></span>
315<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  style</span><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">=</span><span style="--shiki-dark:#98C379;--shiki-light:#032F62;">&quot;height: 640px&quot;</span></span>
316<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  {</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">columns</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">}</span></span>
317<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  {</span><span style="--shiki-dark:#E06C75;--shiki-light:#24292E;">source</span><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">}</span></span>
318<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  rowHeaders</span></span>
319<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  range</span></span>
320<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  filter</span></span>
321<span class="line"><span style="--shiki-dark:#D19A66;--shiki-light:#6F42C1;">  resize</span></span>
322<span class="line"><span style="--shiki-dark:#ABB2BF;--shiki-light:#24292E;">/&gt;</span></span></code></pre></div></div></div><p>The same <a href="/guide/performance">performance rules</a> apply in every integration: keep large inputs stable, use lightweight <a href="/guide/cell/renderer">framework-native renderers</a>, synchronize edits incrementally, and use <a href="/guide/server-side-data">server-side data</a> when the full dataset should not live in the client.</p><p>Continue with the framework-specific setup and customization guides:</p><ul><li><a href="/guide/react/">React data grid guide</a>, <a href="/guide/react/renderer">React renderers</a>, and <a href="/guide/react/editor">React editors</a></li><li><a href="/guide/vue3/">Vue 3 data grid guide</a>, <a href="/guide/vue3/renderer">Vue renderers</a>, and <a href="/guide/vue3/editor">Vue editors</a></li><li><a href="/guide/angular/">
322Angular data grid guide</a>, <a href="/guide/angular/renderer">Angular renderers</a>, and <a href="/guide/angular/editor">Angular editors</a></li><li><a href="/guide/svelte/">Svelte data grid guide</a>, <a href="/guide/svelte/renderer">Svelte renderers</a>, and <a href="/guide/svelte/editor">Svelte editors</a></li><li><a href="/guide/ts/">TypeScript guide</a>, <a href="/guide/">plain JavaScript quick start</a>, and <a href="/guide/standalone">standalone Web Component setup</a></li></ul><h2 id="Data-grid-or-full-spreadsheet-which-should-you-choose-" tabindex="-1">Data grid or full spreadsheet: which should you choose? <a class="header-anchor" href="#Data-grid-or-full-spreadsheet-which-should-you-choose-" aria-label="Permalink to “Data grid or full spreadsheet: which should you choose?”">​</a></h2><p>“Excel-like” does not always mean “build Excel in the browser.”</p><p>Choose an Excel-like data grid when:</p><ul><li>each row maps to a business entity</li><li>your API and database remain authoritative</li><li>columns have known types and permissions</li><li>edits must trigger application rules</li><li>the interface needs custom cells, editors, actions, and status controls</li><li>performance across large row counts matters</li><li>the grid is one part of a larger SaaS or internal application</li></ul><p>Choose a full spreadsheet model when:</p><ul><li>the workbook or document is the primary product</li><li>users should create arbitrary sheets and layouts</li><li>cell coordinates are more important than business-field names</li><li>user-authored formulas define most of the domain logic</li><li>compatibility with existing workbook documents is the central requirement</li></ul><p>Many B2B products do not need a spreadsheet clone. They need <strong>spreadsheet fluency under application control</strong>.</p><h2 id="Implementation-checklist" tabindex="-1">Implementation checklist <a class="header-anchor" href="#Implementation-checklist" aria-label="Permalink to “Implementation checklist”">​</a></h2><p>Before calling an Excel-like grid production-ready, verify the complete workflow:</p><ol><li><strong><a href="/guide/grid.size">Viewport</a>:</strong> The grid has a constrained height and <a href="/guide/performance">row and column virtualization</a> remain enabled.</li><li><strong><a href="/guide/data-sync#framework-notes">Stable inputs</a>:</strong> Columns and active source data are not recreated after every small interaction.</li><li><strong><a href="/guide/editing">Editing</a>:</strong> Read-only and editable fields are explicit.</li><li><strong><a href="/guide/editing#editing-lifecycle-events">Validation</a>:</strong> Invalid values can be rejected or normalized before commit.</li><li><strong><a href="/guide/clipboard">Clipboard</a>:</strong> Multi-cell paste has defined validation, permission, and persistence behavior.</li><li><strong><a href="/guide/data-sync">Synchronization</a>:</strong> Single edits, range edits, paste, and autofill can be saved as patches or batches.</li><li><strong>Failure handling:</strong> The UI defines retry, rollback, conflict, and user-notification behavior.</li><li><strong><a href="/guide/performance">Performance</a>:</strong> Custom cells are measured with realistic data and interaction patterns.</li><li><strong><a href="/guide/server-side-data">Remote data</a>:</strong> The browser loads only the data it should own.</li><li><strong><a href="/guide/wcag">Accessibility</a>:</strong> Keyboard navigation, focus, labels, contrast, and screen-reader behavior are tested in the final product context.</li><li><strong><a href="/guide/data-grid-export-excel">Export</a>:</strong> Exported fields and formulas follow the same permissions as the visible application.</li><li><strong><a href="/guide/security">Security</a>:</strong> Pasted, rendered, and exported content is treated as untrusted application data.</li></ol><h2 id="Start-building" tabindex="-1">Start building <a class="header-anchor" href="#Start-building" aria-label="Permalink to “Start building”">​</a></h2><p>Start with <a href="/guide/licensing">RevoGrid Core</a> for virtualized rendering, editing, clipboard, filtering, and customization. Add <a href="/pro/">RevoGrid Pro</a> only when the application needs formulas, autofill, formatting, history, collaboration, or Excel export.</p><ul><li>Explore the <a href="/excel-data-grid">Excel Data Grid for JavaScript applications</a>.</li><li>Run the <a href="/demo/">interactive RevoGrid demos</a>.</li><li>Review the <a href="/benchmarks">large-data benchmark and methodology</a>.</li><li>Follow the <a href="/guide/">JavaScript Data Grid quick start</a>.</li><li>Evaluate the advanced modules with the <a href="/trial">30-day RevoGrid Pro trial</a>.</li></ul>`,130),a(o,{id:`high-performance-excel-grid-faq`}),n[1]||=r(`<h2 id="Related-reading" tabindex="-1">Related reading <a class="header-anchor" href="#Related-reading" aria-label="Permalink to “Related reading”">​</a></h2><ul><li><a href="/blog/best-js-datagrid-in-2026">Best JavaScript Data Grids in 2026</a></li><li><a href="/blog/build-collaborative-datagrid">Build a Collaborative JavaScript Data Grid</a></li><li><a href="/guide/performance">RevoGrid Performance and Virtualization</a></li><li><a href="/guide/editing">Editing and Validation Events</a></li><li><a href="/guide/clipboard">Clipboard Operations</a></li><li><a href="/guide/data-sync">Data Loading and Synchronization</a></li><li><a href="/compare/ag-grid-alternative/">AG Grid Alternative</a></li><li><a href="/compare/handsontable-alternative/">Handsontable Alternative</a></li></ul>`,2)]))}}),l=e({__pageData:()=>s,default:()=>u}),u=c;export{s as __pageData,u as default,l as t};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.