# RevoGrid Documentation Full Export
Generated from source Markdown for https://rv-grid.com.
Generated type API pages, blog posts, comparison pages, legal policies, and hidden partials are intentionally excluded.
---
# JavaScript Data Grid for Complex Web Apps
Source: https://rv-grid.com/
Description: Build spreadsheet-grade data grids with Vue, React, Angular, Svelte, Dash, Python, and JavaScript apps.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# React Data Grid — Fast, Editable, Virtual Scroll | RevoGrid
Source: https://rv-grid.com/react-data-grid
Description: A high-performance React data grid with virtual scrolling, inline editing, and custom React cell renderers. Open-source core, per-developer licensing, built for data-heavy React apps.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# Vue Data Grid - Fast, Editable, Virtual Scroll | RevoGrid
Source: https://rv-grid.com/vue-data-grid
Description: A high-performance Vue data grid with virtual scrolling, inline editing, and custom Vue cell renderers. Open-source core, per-developer licensing, built for data-heavy Vue 3 apps.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# Angular Data Grid - Fast, Editable, Virtual Scroll | RevoGrid
Source: https://rv-grid.com/angular-data-grid
Description: A high-performance Angular data grid with virtual scrolling, inline editing, and custom Angular cell renderers. Open-source core, per-developer licensing, built for data-heavy Angular apps.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# Svelte Data Grid - Fast, Editable, Virtual Scroll | RevoGrid
Source: https://rv-grid.com/svelte-data-grid
Description: A high-performance Svelte data grid with virtual scrolling, inline editing, and custom Svelte cell renderers. Open-source core, per-developer licensing, built for data-heavy Svelte apps.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# RevoGrid Pro
Source: https://rv-grid.com/pro
Description: JavaScript Kanban, Pivot, Gantt, Scheduling, Spreadsheet formulas, master-detail grids, and audit history without building the data layer from scratch.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# RevoGrid Pro Pricing and Feature Comparison
Source: https://rv-grid.com/pro/feature-table
Description: Compare RevoGrid Community, Pro Lite, and Pro Advanced plans, including advanced grid features, support options, and upgrade paths.
# RevoGrid Pro pricing and feature comparison
[Watch the feature overview](https://rv-grid.com/pro)
Choose this page when you need a quick answer to:
- which advanced features are included in each plan
- whether a feature is part of Community or Pro
- which plan includes advanced support
For a higher-level overview, go back to [RevoGrid Pro](https://rv-grid.com/pro/).
### Useful links
[Privacy Policy](https://rv-grid.com/pro/policies/privacy) | [Terms of Service](https://rv-grid.com/pro/policies/terms) | [License](https://rv-grid.com/pro/policies/license) | [Security Policy](https://rv-grid.com/pro/policies/security) | Contact us
### Frequently asked questions
::: details How many developer licenses do I need?
The number of licenses required must match the maximum number of concurrent developers contributing to the front-end code.
**Examples:**
- **Example 1**: A project has 3 front-end developers and 10 back-end developers. If only the 3 front-end developers work with RevoGrid Pro, you need 3 licenses.
- **Example 2**: A UI team with 2 front-end developers uses RevoGrid Pro as part of a shared library for multiple apps. If the apps have 5 and 3 front-end developers, you will need 10 licenses (2 + 5 + 3).
For more details, refer to the relevant clause in the [EULA](https://rv-grid.com/pro/policies/license#_3-4-1-Required-quantity-of-licenses).
:::
::: details Am I allowed to use the product after the update entitlement expires?
Yes, you can continue using the product in production environments after the update entitlement expires.
**However**:
- You need an active subscription to continue development.
- Updates, new features, and technical support require a valid subscription.
To renew, contact [sales](mailto:contact@revolist.eu).
:::
::: details Do developers have to be named?
No. Licenses are transferable between developers when team members join or leave projects.
We trust that your team will not exceed the number of licensed developers.
:::
::: details What is the policy on redistributing the software?
RevoGrid Pro licenses are royalty-free for:
- Internal company solutions.
- Hosted applications.
- Commercial solutions deployed to end users.
If sublicensing is needed, it must be part of a larger work, and sublicenses must follow the same [EULA terms](https://rv-grid.com/pro/policies/license).
Examples:
- **Example 1:** Agency ‘A’ builds apps for two clients and sublicenses RevoGrid components. No extra fee is needed if the apps are used without source modification.
- **Example 2:** If clients modify the application themselves, they must purchase their own licenses.
For custom use cases or licensing concerns, please [contact sales](mailto:contact@revolist.eu).
:::
::: details Do you offer discounts to educational and non-profit organizations?
Yes, we offer a 50% discount for students, instructors, non-profits, and charities.
To qualify:
- Provide proof of affiliation (e.g., an email from an official account).
[Contact sales](mailto:contact@revolist.eu) to apply.
:::
::: details Why must we license developers not using the software directly?
All developers contributing to a project using RevoGrid Pro must be licensed, even if they only use it indirectly (e.g., via a wrapper library).
This ensures fair licensing and helps teams comply easily. The per-developer price is adjusted to account for this broader requirement.
Learn more in the [EULA](https://rv-grid.com/pro/policies/license).
:::
::: details Need Help? {open dashed}
If you have questions or need support, reach out:
- For sales-related inquiries: [contact sales](mailto:contact@revolist.eu).
- For product issues, [open a GitHub issue](https://github.com/revolist/revogrid/issues).
:::
:::: details Is there a deployment fee?
No. RevoGrid Pro does not currently charge a deployment fee.
Your license costs are based on the selected plan and the required number of developer licenses, not on how many times you deploy.
For custom licensing questions, please [contact sales](mailto:contact@revolist.eu).
::::
---
# RevoGrid Pro Feature Videos and Demos
Source: https://rv-grid.com/pro/videos
Description: Watch RevoGrid Pro feature videos and interactive demos for advanced data grid plugins, editing, layout, filtering, validation, and enterprise workflows.
# RevoGrid Pro Feature Videos
Click on the features below to see video previews, explore the feature demos below, or [compare our plans](https://rv-grid.com/pro).
### Frequently asked questions
::: details How many developer licenses do I need?
The number of licenses required must match the maximum number of concurrent developers contributing to the front-end code.
**Examples:**
- **Example 1**: A project has 3 front-end developers and 10 back-end developers. If only the 3 front-end developers work with RevoGrid Pro, you need 3 licenses.
- **Example 2**: A UI team with 2 front-end developers uses RevoGrid Pro as part of a shared library for multiple apps. If the apps have 5 and 3 front-end developers, you will need 10 licenses (2 + 5 + 3).
For more details, refer to the relevant clause in the [EULA](https://rv-grid.com/pro/policies/license#_3-4-1-Required-quantity-of-licenses).
:::
::: details Am I allowed to use the product after the update entitlement expires?
Yes, you can continue using the product in production environments after the update entitlement expires.
**However**:
- You need an active subscription to continue development.
- Updates, new features, and technical support require a valid subscription.
To renew, contact [sales](mailto:contact@revolist.eu).
:::
::: details Do developers have to be named?
No. Licenses are transferable between developers when team members join or leave projects.
We trust that your team will not exceed the number of licensed developers.
:::
::: details What is the policy on redistributing the software?
RevoGrid Pro licenses are royalty-free for:
- Internal company solutions.
- Hosted applications.
- Commercial solutions deployed to end users.
If sublicensing is needed, it must be part of a larger work, and sublicenses must follow the same [EULA terms](https://rv-grid.com/pro/policies/license).
Examples:
- **Example 1:** Agency ‘A’ builds apps for two clients and sublicenses RevoGrid components. No extra fee is needed if the apps are used without source modification.
- **Example 2:** If clients modify the application themselves, they must purchase their own licenses.
For custom use cases or licensing concerns, please [contact sales](mailto:contact@revolist.eu).
:::
::: details Do you offer discounts to educational and non-profit organizations?
Yes, we offer a 50% discount for students, instructors, non-profits, and charities.
To qualify:
- Provide proof of affiliation (e.g., an email from an official account).
[Contact sales](mailto:contact@revolist.eu) to apply.
:::
::: details Why must we license developers not using the software directly?
All developers contributing to a project using RevoGrid Pro must be licensed, even if they only use it indirectly (e.g., via a wrapper library).
This ensures fair licensing and helps teams comply easily. The per-developer price is adjusted to account for this broader requirement.
Learn more in the [EULA](https://rv-grid.com/pro/policies/license).
:::
::: details Need Help? {open dashed}
If you have questions or need support, reach out:
- For sales-related inquiries: [contact sales](mailto:contact@revolist.eu).
- For product issues, [open a GitHub issue](https://github.com/revolist/revogrid/issues).
:::
:::: details Is there a deployment fee?
No. RevoGrid Pro does not currently charge a deployment fee.
Your license costs are based on the selected plan and the required number of developer licenses, not on how many times you deploy.
For custom licensing questions, please [contact sales](mailto:contact@revolist.eu).
::::
---
# Fast JavaScript Pivot Table for Web
Source: https://rv-grid.com/pivot
Description: JavaScript Pivot Table with linked charts for React, Vue, Angular, or vanilla JavaScript applications.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# JavaScript Kanban Board Component
Source: https://rv-grid.com/kanban
Description: RevoGrid Kanban is a virtualized JavaScript Kanban board component for drag-and-drop workflows, swimlanes, WIP limits, custom cards, and large task datasets.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# JavaScript Gantt Chart Component
Source: https://rv-grid.com/gantt
Description: RevoGrid Gantt is a fast JavaScript Gantt chart for data-heavy web apps, with virtualization, dependencies, resources, critical path, and a live 10,000-task demo.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# JavaScript Scheduler & Event Calendar | RevoGrid Scheduler
Source: https://rv-grid.com/jsscheduler
Description: RevoGrid Scheduler is a JavaScript Scheduler and event calendar for resource timelines, staff shifts, bookings, availability, and capacity planning.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# JavaScript Data Grid Quick Start
Source: https://rv-grid.com/guide
Description: Learn how to install RevoGrid, render your first JavaScript data grid, and move from a basic setup to filtering, editing, and framework integrations.
RevoGrid is a high-performance [MIT-licensed](https://rv-grid.com/guide/licensing) JavaScript data grid built for large datasets, fast scrolling, and spreadsheet-like interactions. It works as a Web Component, so the same core grid can be used in JavaScript, [TypeScript](https://rv-grid.com/guide/ts/), [React](https://rv-grid.com/guide/react/), [Angular](https://rv-grid.com/guide/angular/), [Vue](https://rv-grid.com/guide/vue3/), [Svelte](https://rv-grid.com/guide/svelte/), and other modern frontends.
[Explore the full RevoGrid Data Grid →](https://rv-grid.com/)
## Quick start in 60 seconds
This page is the fastest way to get a JavaScript data grid on the screen with RevoGrid. From here you can move into feature guides, framework-specific setup, and the full [API](https://rv-grid.com/guide/api/revoGrid).
For prototypes, internal tools, or plain HTML pages, load RevoGrid directly from a CDN:
```html
```
## Why teams use RevoGrid
- [Virtual rows and columns](https://rv-grid.com/guide/performance) keep rendering fast as datasets grow.
- Built-in [focus](https://rv-grid.com/guide/defs#Focus), [range selection](https://rv-grid.com/guide/defs#Range), [editing](https://rv-grid.com/guide/editing), [sorting](https://rv-grid.com/guide/sorting), [filtering](https://rv-grid.com/guide/filters), [column pinning](https://rv-grid.com/guide/column/pin), and [row pinning](https://rv-grid.com/guide/row/pin) cover common grid workflows.
- The same [`` core](https://rv-grid.com/guide/defs#Web-Component) works across multiple frameworks.
- Public [methods](https://rv-grid.com/guide/programmatic-control) and [events](https://rv-grid.com/guide/api/events) make it possible to build custom workflows without forking the grid.
:::tip
RevoGrid's [API](https://rv-grid.com/guide/api/revoGrid) is consistent across all major frameworks. Transfer your experience and knowledge from one framework to another.
:::
:::warning Can't find your framework?
[Ask us](https://github.com/revolist/revogrid/discussions) or [open an issue](https://github.com/revolist/revogrid/issues/new?assignees=&labels=&projects=&template=new-issue.md&title=) on GitHub.
:::
Angular – Setup and usage in Angular environments.
Vue 3 – Detailed guide for integrating with Vue 3.
# JavaScript Data Grid Demo
Use this standalone JavaScript demo to see RevoGrid render editable tabular data with virtual scrolling and fast browser performance.
:::preview #demo-overview .rv-overview :path /demo/js/js.overview.example
:::
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/js/js.overview.example.ts) [Codesandbox](https://codesandbox.io/p/sandbox/rg-quick-overview-88rf36?from-embed=)
::: code-group
<<< @/demo/js/js.overview.example.ts#snippet
<<< @/json/stock.json
:::
## Basic setup with a custom cell template
RevoGrid can stay simple for read-only tables, or become interactive with custom renderers, editors, and events. This example adds a richer cell template while keeping the same grid setup:
```typescript
// Snag your grid element from the DOM
const grid = document.querySelector('revo-grid');
// Let the grid know about your columns and data
grid.columns = [
{ prop: 'first', name: 'First column' },
{
prop: 'second',
name: 'Second column',
// Spice up your cell with a custom template
cellTemplate: (h, { value }) => h('div', {
style: { backgroundColor: 'red' }, // Because red is fast
}, value || '')
}
];
// Here's your data, ready to be displayed
grid.source = [{
first: 'New item',
second: 'Item description'
//... Add more rows as needed
}];
```
## Next steps
Choose the path that matches what you are building:
- [Installation](https://rv-grid.com/guide/installation): package managers, CDN usage, and loader setup.
- [Get Pro Trial](https://rv-grid.com/trial): install the 30-day Pro trial and compare public demos before purchasing.
- [Overview](https://rv-grid.com/guide/overview): how the grid is structured and when to use it.
- [AI Agents and MCP](https://rv-grid.com/guide/mcp): connect Codex, Cursor, Claude Code, or VS Code to version-aware RevoGrid docs, examples, migrations, and typed API context.
- [Filtering](https://rv-grid.com/guide/filters): enable built-in filtering and custom filter logic.
- [Editing](https://rv-grid.com/guide/editing): inline editing, events, and read-only behavior.
- [Understanding Viewports](https://rv-grid.com/guide/viewports): physical vs virtual indexes, pinned areas, and event coordinates.
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control): methods such as `setDataAt`, `setCellEdit`, and `scrollToRow`.
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration): `columnTypes`, `rowDefinitions`, `trimmedRows`, `additionalData`, and plugin-oriented hooks.
## Framework guides
If you are integrating RevoGrid into an application framework, start with the wrapper guide for your stack:
- [TypeScript](https://rv-grid.com/guide/ts/)
- [React](https://rv-grid.com/guide/react/)
- [Angular](https://rv-grid.com/guide/angular/)
- [Vue 3](https://rv-grid.com/guide/vue3/)
- [Svelte](https://rv-grid.com/guide/svelte/)
## Example
[](https://codesandbox.io/p/sandbox/revogrid-60s-tlxgwn)
---
# RevoGrid Installation
Source: https://rv-grid.com/guide/installation
Description: Install RevoGrid with npm, pnpm, yarn, bun, or a CDN, then register the Web Components loader for JavaScript or TypeScript projects.
You can use RevoGrid in three common ways:
- package manager installation for app projects
- direct CDN usage for prototypes or no-build pages
- framework wrappers for React, Angular, Vue, and Svelte
If you are not sure where to start, use the package-manager flow and register the custom elements loader once in your application entrypoint.
:::tip
RevoGrid's [API](https://rv-grid.com/guide/api/revoGrid) is consistent across all major frameworks. Transfer your experience and knowledge from one framework to another.
:::
:::warning Can't find your framework?
[Ask us](https://github.com/revolist/revogrid/discussions) or [open an issue](https://github.com/revolist/revogrid/issues/new?assignees=&labels=&projects=&template=new-issue.md&title=) on GitHub.
:::
Angular – Setup and usage in Angular environments.
Vue 3 – Detailed guide for integrating with Vue 3.
## Install from a package manager
Install the core package:
::: code-group
```npm
npm i @revolist/revogrid
```
```pnpm
pnpm add @revolist/revogrid
```
```yarn
yarn add @revolist/revogrid
```
```bun
bun add @revolist/revogrid
```
:::
## Register the Web Components loader
RevoGrid ships as Web Components. Register them once before rendering any grid:
```ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();
```
This is the standard entrypoint for JavaScript and TypeScript applications. If you are using a framework wrapper, its own installation guide will show the package to install and the wrapper-specific setup.
## Minimal JavaScript or TypeScript setup
Once the loader is registered, render the grid and assign data:
```ts
const grid = document.querySelector('revo-grid');
grid.columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'email', name: 'Email' },
];
grid.source = [
{ name: 'Ada Lovelace', email: 'ada@example.com' },
{ name: 'Grace Hopper', email: 'grace@example.com' },
];
```
## No-build integration
For a quick proof of concept, load the grid directly from a CDN.
### Script tag
```html
```
### ES modules
```html
```
Use the module version when you want to register the standalone custom element from an ES module.
## Which package should you install?
- Core JavaScript/TypeScript: `@revolist/revogrid`
- React wrapper: start at [React Data Grid](https://rv-grid.com/guide/react/)
- Angular wrapper: start at [Angular Data Grid](https://rv-grid.com/guide/angular/)
- Vue 3 wrapper: start at [Vue 3 Data Grid](https://rv-grid.com/guide/vue3/)
- Svelte wrapper: start at [Svelte Data Grid](https://rv-grid.com/guide/svelte/)
Evaluating Pro or Pro Advanced modules? Use [Get Pro Trial](https://rv-grid.com/trial) to install the 30-day trial, review public demos, and understand the path from evaluation to production.
## Common next steps
- [Quick Start](https://rv-grid.com/guide/): first grid in plain JavaScript.
- [TypeScript Data Grid](https://rv-grid.com/guide/ts/): typed columns and data models.
- [Standalone and ES Modules](https://rv-grid.com/guide/standalone): framework-free module usage.
- [SSR](https://rv-grid.com/guide/ssr): when the browser-only runtime affects your app shell.
---
# JavaScript Data Grid Overview
Source: https://rv-grid.com/guide/overview
Description: Learn what RevoGrid provides for high-performance JavaScript data grids, including virtual scrolling, framework support, custom cells, editing, and large dataset workflows.
So, you have an app that manages intensive datasets and you might think it’s straightforward enough to handle on your own. After all, implementing virtual scrolling might seem like all it takes.
> But what happens when your needs grow?
Suppose you want to [`pin`](https://rv-grid.com/guide/defs#Row-Pin-Freeze) a row at the top or bottom. [`Add a column`](https://rv-grid.com/guide/defs#Column) that also needs to be pinned. And then start [`grouping`](https://rv-grid.com/guide/defs#Row-Grouping) these elements. Soon, you might find yourself needing [`cell focus`](https://rv-grid.com/guide/defs#Focus) and [`range selections`](https://rv-grid.com/guide/defs#Range). This is where the complexity increases significantly.
In scenarios like this, maintaining performance while adding sophisticated grid functionalities can become difficult.
## Motivation
Confronted with vast data streams, we realized the limitations of existing solutions: while on-market 3rd-party libraries offered temporary respite, they came with their own set of challenges—prompting us to think beyond conventional method:
> Our goal is to create a truly reactive datagrid core, one that could stand shoulder to shoulder with any framework while being universally accessible for developers and organizations alike. It's designed to handle the most demanding data without compromising on performance, ensuring that your applications run smoothly and efficiently.
## Magic behind the scene
`RevoGrid` is built on top of [StencilJS](https://stenciljs.com/) (a compiler for building fast web apps using Web Components), leveraging the power of a reactive DOM to ensure optimal performance and responsiveness. Its architecture is *designed to handle large datasets* with ease, providing a seamless user experience even in data-intensive applications.
This approach allows RevoGrid to be **framework-agnostic**, ensuring developers can integrate it into any project regardless of the underlying technology stack.
## VNode Reactive DOM
At the core of RevoGrid's high performance is its use of a reactive DOM model (similar one you would find in any popular reactive framework [Vue Virtual DOM](https://vuejs.org/guide/extras/rendering-mechanism), [React Virtual DOM](https://legacy.reactjs.org/docs/faq-internals.html), etc.). This model ensures that only the parts of the grid that need updating are re-rendered, rather than the entire grid. This selective rendering mechanism is crucial for handling large amounts of data, as it significantly reduces the amount of DOM manipulation required, leading to smoother scrolling and interactions.
## Framework Native Support
We have built native support for all popular frameworks, enabling you to integrate native elements directly inside the grid cells. For example, you can embed Vue/React/Angular components within RevoGrid, allowing for a rich and interactive data grid experience.
To use native elements in your grid, simply utilize our providers. This feature enhances flexibility and allows you to leverage the unique capabilities of each framework while maintaining a unified grid experience.
For more detailed information on implementing this functionality, be sure to read the relevant sections of our documentation.
:::tip
RevoGrid's [API](https://rv-grid.com/guide/api/revoGrid) is consistent across all major frameworks. Transfer your experience and knowledge from one framework to another.
:::
:::warning Can't find your framework?
[Ask us](https://github.com/revolist/revogrid/discussions) or [open an issue](https://github.com/revolist/revogrid/issues/new?assignees=&labels=&projects=&template=new-issue.md&title=) on GitHub.
:::
Angular – Setup and usage in Angular environments.
Vue 3 – Detailed guide for integrating with Vue 3.
## Why to choose?
`RevoGrid` is an essential tool for developers aiming to build high-quality, data-intensive applications.
RevoGrid distinguishes itself from other data grids with its unwavering commitment to user experience. Our `advanced scrolling` technology ensures seamless navigation through vast datasets—this finely tuned interaction is what sets us apart. Additionally, we support native behavior for `optimal out-of-browser performance` and features rapid cell rendering and updates, ensuring the application remains responsive at all times. These capabilities make us not just different, but superior in facilitating an efficient and smooth user interface.
::: info If you find yourself constantly pondering over questions like
- Why is my application slowing down?
- Should I enable paging to speed it up?
- How can I manage such large volumes of data efficiently?
- It looks like an Excel sheet; can it perform well?
:::
Its highly competitive feature set and performance can be applied in various areas and industries. Here are our real-case scenarios where you can improve data management and user experience to a granular level.
## Where to apply?
- ### Financial Modeling and Analysis
Financial institutions and fintech startups can leverage RevoGrid for complex financial modeling and analysis. The grid's performance in handling large volumes of data, coupled with its support for custom cell formatting and editing, makes it ideal for real-time financial analysis, budgeting, and forecasting.
- ### Project Management Tools
Project management software can benefit from RevoGrid's capabilities to track tasks, deadlines, and progress across multiple projects. The grid's flexibility and performance make it suitable for creating detailed project dashboards that enhance team collaboration and efficiency.
- ### E-Commerce Dashboards
E-commerce platforms can use RevoGrid to manage large inventories, track orders, and analyze customer data. The grid's efficient data rendering and manipulation capabilities allow for real-time updates and seamless user interactions, crucial for monitoring sales trends and inventory levels.
- ### Healthcare Data Management
Healthcare applications can benefit from RevoGrid's ability to handle large datasets, such as patient records, appointment schedules, and treatment histories. The grid's sorting, filtering, and editing features enable healthcare professionals to quickly access and manage patient information, improving the efficiency of care delivery.
- ### Educational Platforms
Educational software, including learning management systems (LMS), can use RevoGrid to display and manage student data, course materials, and grades. The grid's customizable nature allows for the creation of intuitive interfaces that cater to the diverse needs of educators and students.
- ### Real Estate Portals
Real estate platforms can utilize RevoGrid to display property listings, including detailed information such as images, descriptions, prices, and agent contacts. The grid's virtual scrolling and efficient data rendering ensure a smooth user experience, even with thousands of listings.
- ### Logistics and Supply Chain Management
For logistics and supply chain applications, RevoGrid can manage and display shipping schedules, inventory levels, and transport routes. Its high performance and dynamic data manipulation capabilities support the complex, real-time data needs of logistics operations.
## Find guides for your framework
:::tip
RevoGrid's [API](https://rv-grid.com/guide/api/revoGrid) is consistent across all major frameworks. Transfer your experience and knowledge from one framework to another.
:::
:::warning Can't find your framework?
[Ask us](https://github.com/revolist/revogrid/discussions) or [open an issue](https://github.com/revolist/revogrid/issues/new?assignees=&labels=&projects=&template=new-issue.md&title=) on GitHub.
:::
Angular – Setup and usage in Angular environments.
Vue 3 – Detailed guide for integrating with Vue 3.
---
# Data Source Loading and Syncing
Source: https://rv-grid.com/guide/data-sync
Description: Choose how RevoGrid should receive, own, and synchronize row data across JavaScript, TypeScript, React, Vue, Angular, and Svelte applications.
When you work with any JS Data Grid or complex component, most of the time the framework changes, but the data question is the same:
> Who owns the edited data?
Once that is clear, integration becomes much easier.
## Start with ownership
| Approach | What it means | Use it when |
| --- | --- | --- |
| Grid-owned data | RevoGrid edits the row objects passed to `source` | The grid is a local draft, import tool, spreadsheet, or save-on-submit UI |
| App-owned data | Your store or server model owns the final value | Other screens, validation, autosave, audit logs, or collaboration need the edits |
Both approaches work. Problems usually start when a reactive app replaces the whole grid source after every edit:
```txt
cell edit -> app state update -> new source array -> grid receives a new dataset
```
That looks natural in many frameworks, but it is expensive for a virtual grid. A new `source` is treated as a dataset-level change. It can reset or disturb selection, focus, editor state, scroll position, history, dirty tracking, and plugin state.
For normal editing, keep the active `source` stable and sync only the changed value.
## How editing works
RevoGrid reads and writes the row objects in `source`.
```ts
const source = [
{ id: 1, name: 'Apple', price: 1.2 },
{ id: 2, name: 'Banana', price: 0.5 },
];
grid.source = source;
grid.columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'price', name: 'Price' },
];
```
If a user edits the first row price, the same row object receives the new `price`. RevoGrid does not need a fresh array just to show that edit.
## Option 1: Let the grid own the draft
This is the simplest model. Pass rows to the grid, let users edit, and read the data when you need to save.
```ts
grid.source = source;
async function save() {
const rows = await grid.getSource();
await saveRows(rows);
}
```
Use this when the rest of the app does not need to react immediately to every cell edit.
## Option 2: Listen after edits
Use `afteredit` when the grid should apply the edit first, then your app should hear about the changed field.
```ts
grid.addEventListener('afteredit', event => {
const { model, prop, val } = event.detail;
updateStore(model.id, prop, val);
});
```
This should be an incremental sync. Do not immediately rebuild `source` from the store and pass it back to the grid for the same edit.
Use `beforeedit` or `beforerangeedit` when you need to block or normalize a value before it is saved:
```ts
grid.addEventListener('beforeedit', event => {
if (event.detail.prop === 'price' && Number(event.detail.val) < 0) {
event.preventDefault();
}
});
```
## Option 3: Use a proxy source
A proxy source is useful when your store must see writes immediately, but RevoGrid still needs stable row objects.
```ts
function createRowProxy(row, updateStore) {
return new Proxy(row, {
set(target, prop, value) {
Reflect.set(target, prop, value);
updateStore(target.id, prop, value);
return true;
},
});
}
grid.source = rows.map(row => createRowProxy(row, updateStore));
```
The flow is:
```txt
cell edit -> proxy setter -> app store
```
Create proxies once for the active dataset. Do not create a new proxy array on every render. For the full pattern, see [Proxy Source Editing](https://rv-grid.com/guide/proxy-source).
## Option 4: Keep a patch layer
Use patches when you want dirty tracking, review-before-save, validation flows, or batch submit.
```ts
const patches = {};
grid.addEventListener('afteredit', event => {
const { model, prop, val } = event.detail;
patches[model.id] ??= {};
patches[model.id][prop] = val;
});
function getResolvedValue(row, prop) {
return patches[row.id]?.[prop] ?? row[prop];
}
```
This keeps the grid data stable while your app tracks the changes separately.
## Option 5: Batch external sync
Use a queue when edits should go to a store, API, or analytics pipeline, but not one by one.
```ts
const queue = [];
let flushTimer = 0;
grid.addEventListener('afteredit', event => {
queue.push(event.detail);
scheduleFlush();
});
function scheduleFlush() {
if (!flushTimer) {
flushTimer = window.setTimeout(flush, 250);
}
}
function flush() {
flushTimer = 0;
updateStoreBatch(queue.splice(0));
}
```
This works well for autosave, paste, fill, and high-volume editing.
## Framework notes
Different frameworks express reactivity differently, but the practical rule stays the same: stable grid inputs, incremental edit sync.
| Environment | Prefer | Avoid |
| --- | --- | --- |
| JavaScript / TypeScript | Create `source` once for the active dataset | Reassigning `grid.source` after every edit |
| React | Keep active rows in `useMemo`, `useRef`, or a store adapter | Creating a fresh `source` from `setState` on each `afteredit` |
| Vue | Use stable state, `shallowRef`, or a store adapter | Deep reactive churn that rebuilds row objects |
| Angular | Keep `source` as a stable field, signal value, or adapter result | Replacing `[source]` every time `(afteredit)` fires |
| Svelte | Keep the array reference stable or sync through a store adapter | Reassigning the `source` prop for each edited cell |
Reactive UI state is good for screens. RevoGrid also has viewport, focus, editing, and plugin state. Treat full `source` replacement as loading a dataset, not as the default way to handle a cell edit.
## Replace `source` when the dataset changes
Full replacement is correct for:
- initial load
- page change
- dataset switch
- server refresh
- filter or search result replacement
- server-side pagination, sorting, filtering, or grouping result replacement
- adding, removing, or reordering rows outside the grid
- switching from draft data to confirmed server data
For targeted cell changes from application code, use methods such as `setDataAt` from [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control). For live streams, see [Real-Time Updates in RevoGrid](https://rv-grid.com/guide/realtime-updates).
## Quick checklist
- Decide whether the grid or the app owns edits.
- Keep `source` and `columns` stable while editing.
- Use `afteredit` for post-edit sync.
- Use `beforeedit` or `beforerangeedit` for validation or cancellation.
- Use proxy, patch, or queue patterns when the app needs more control.
- Replace the full source only when the dataset itself changes.
## Rule of thumb
Good:
```txt
cell edit -> afteredit/proxy/patch/queue -> incremental app sync
```
Problematic:
```txt
cell edit -> recreate full source -> grid receives new dataset
```
## Related guides
- [Proxy Source Editing](https://rv-grid.com/guide/proxy-source)
- [State Persistence](https://rv-grid.com/guide/state-persistence)
- [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [RevoGrid Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
- [Real-Time Updates in RevoGrid](https://rv-grid.com/guide/realtime-updates)
- [RevoGrid Best Practices](https://rv-grid.com/guide/patterns)
---
# RevoGrid State Persistence
Source: https://rv-grid.com/guide/state-persistence
Description: Save and restore RevoGrid user state including column order, column width, pinned columns, sorting, filtering, selection, scroll position, layout presets, and Pro workspace state.
Grid users expect their workspace to survive reloads, device switches, saved views, and product releases. Common state includes column order, widths, pinned columns, sorting, filters, selection, scroll position, grouping, pivot fields, Gantt preferences, and named layout presets.
RevoGrid keeps this practical: your application owns the persisted state, and RevoGrid exposes the props, methods, and events needed to collect and restore it. Instead of relying on one monolithic `getGridState()` object, persist the pieces your product actually supports.
## What to persist
Start with a small state object and extend it as users need more saved workspace behavior.
```ts
type PersistedFilterState = {
collection: Record<
string,
{
type:
| 'empty'
| 'notEmpty'
| 'eq'
...;
value: unknown;
}
>;
};
type PersistedGridState = {
version: 1;
schema: string;
columnOrder: string[];
columnWidths: Record;
pinnedColumns: {
start: string[];
end: string[];
};
sorting?: {
columns?: {
prop: string;
order: 'asc' | 'desc';
}[];
};
filter?: PersistedFilterState;
selection?: {
x: number;
y: number;
x1: number;
y1: number;
} | null;
scroll?: {
row?: number;
columnProp?: string;
};
grouping?: unknown;
pivot?: unknown;
gantt?: unknown;
preferences?: {
density?: 'compact' | 'comfortable';
theme?: string;
};
layoutPreset?: string;
};
```
Use stable column `prop` values as the durable identifiers. Avoid persisting virtual indexes as the primary state because indexes change when columns are reordered, pinned, hidden, filtered, or replaced.
## Save to localStorage
This example stores column order, sorting, filtering, selection, and scroll state. It keeps the shape app-owned so you can add product-specific preferences later.
:::preview #demo-state-persistence .rv-overview :path /demo/js/js.state-persistence.example
:::
:::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/js/js.state-persistence.example.ts)
::: code-group
<<< @/demo/js/js.state-persistence.example.ts#snippet
:::
::::
## Restore on page load
Restore structural state before assigning `columns`, then restore scroll and selection after the grid has rendered.
```ts
function applyPersistedColumns(columns, state) {
if (!state) {
return columns;
}
const order = new Map(
(state.columnOrder ?? []).map((prop, index) => [prop, index]),
);
const sorting = new Map(
(state.sorting?.columns ?? []).map(column => [
String(column.prop),
column.order,
]),
);
return [...columns]
.map(column => ({
...column,
size: state.columnWidths?.[String(column.prop)] ?? column.size,
pin: getPersistedPin(column.prop, state),
order: sorting.get(String(column.prop)),
}))
.sort((a, b) => {
const left = order.get(String(a.prop)) ?? Number.MAX_SAFE_INTEGER;
const right = order.get(String(b.prop)) ?? Number.MAX_SAFE_INTEGER;
return left - right;
});
}
function getPersistedPin(prop, state) {
const key = String(prop);
if (state.pinnedColumns?.start?.includes(key)) {
return 'colPinStart';
}
if (state.pinnedColumns?.end?.includes(key)) {
return 'colPinEnd';
}
return undefined;
}
async function restoreViewport(grid, state) {
if (state?.scroll?.row !== undefined) {
await grid.scrollToRow(state.scroll.row);
}
if (state?.scroll?.columnProp) {
await grid.scrollToColumnProp(state.scroll.columnProp);
}
if (state?.selection) {
await grid.setCellsFocus(
{ x: state.selection.x, y: state.selection.y },
{ x: state.selection.x1, y: state.selection.y1 },
);
}
}
```
For scroll restoration, prefer row ids or business cursors when your dataset changes often. Numeric row coordinates are useful for restoring a viewport in the same dataset, but they may point to different records after server refreshes, filtering, or row insertion.
## Save to a backend
Use the same state object for backend persistence. Debounce writes so resize, scroll, filtering, and drag operations do not create excessive requests.
```ts
let saveTimer = 0;
let pendingState = {};
function queueBackendState(partial) {
pendingState = { ...pendingState, ...partial };
window.clearTimeout(saveTimer);
saveTimer = window.setTimeout(async () => {
const body = {
gridId: 'orders',
state: {
version: 1,
schema: createSchemaKey(baseColumns),
...loadGridState(),
...pendingState,
},
};
pendingState = {};
await fetch('/api/grid-state/orders', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(body),
});
}, 400);
}
grid.addEventListener('filterconfigchanged', event => {
queueBackendState({ filter: event.detail });
});
grid.addEventListener('sortingconfigchanged', event => {
queueBackendState({ sorting: event.detail });
});
```
Backend state should be scoped by user, tenant, product area, grid id, and layout preset. Keep row data and workspace state separate: row edits belong in your data model, while grid state belongs in user preferences.
## Handle schema changes
Persisted state lasts longer than one release. Version it, store a schema key, and ignore state for columns that no longer exist.
```ts
function createSchemaKey(columns) {
return columns.map(column => String(column.prop)).sort().join('|');
}
function normalizeStateForColumns(state, columns) {
if (!state) {
return null;
}
const validProps = new Set(columns.map(column => String(column.prop)));
return {
...state,
schema: createSchemaKey(columns),
columnOrder: (state.columnOrder ?? []).filter(prop => validProps.has(prop)),
columnWidths: Object.fromEntries(
Object.entries(state.columnWidths ?? {}).filter(([prop]) =>
validProps.has(prop),
),
),
pinnedColumns: {
start: (state.pinnedColumns?.start ?? []).filter(prop =>
validProps.has(prop),
),
end: (state.pinnedColumns?.end ?? []).filter(prop =>
validProps.has(prop),
),
},
};
}
```
New columns should fall back to your default column definitions. Removed columns should be dropped from persisted order, width, pinning, sorting, filtering, and presets.
## Version persisted state
Use a version number when state can outlive a release. Migrate old shapes at load time and save the new shape after a successful restore.
```ts
function migrateGridState(state) {
if (!state) {
return null;
}
if (state.version === 1) {
return state;
}
if (state.version === undefined) {
return {
version: 1,
schema: state.schema ?? '',
columnOrder: state.columns ?? [],
columnWidths: state.widths ?? {},
pinnedColumns: {
start: state.pinnedStart ?? [],
end: state.pinnedEnd ?? [],
},
sorting: state.sorting,
filter: state.filter,
};
}
return null;
}
```
If migration fails, discard the saved state for that grid and load the default layout. A broken preference should not block users from opening the grid.
## Pro and advanced state
Persist advanced feature state the same way: keep the plugin or feature config in your application state, save the user-controlled parts, and restore them before rendering the grid.
| Feature | Persist |
| --- | --- |
| Row grouping | Grouping props, expanded groups, and user-selected grouping presets. |
| Tree data | Expanded row ids and hierarchy display preferences. |
| Pivot | Rows, columns, values, filters, aggregations, subtotals, grand totals, drill-down or expanded paths, and selected report preset. |
| Gantt | Timeline scale, visible date window, task columns, collapsed task groups, dependency visibility, resource filters, and scheduling preferences. |
| Layout presets | A named collection of columns, sorting, filters, plugin config, and product-specific preferences. |
Do not mix persisted workspace state with editable business data. For example, Gantt task dates, dependencies, and assignments usually belong in your project data API. The user's preferred timeline zoom or visible columns belong in grid state.
## Quick checklist
- Use stable column `prop` values.
- Persist only state your product can restore.
- Restore columns, pinning, filters, and sorting before viewport state.
- Restore scroll and selection after the grid is ready.
- Debounce backend saves.
- Version saved state and migrate or discard old shapes.
- Drop state for columns that no longer exist.
- Keep row data synchronization separate from workspace preferences.
## Related guides
- [Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync)
- [Column Ordering](https://rv-grid.com/guide/column/order)
- [Column Pinning](https://rv-grid.com/guide/column/pin)
- [Filtering](https://rv-grid.com/guide/filters)
- [Data Grid Sorting](https://rv-grid.com/guide/sorting)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Understanding Viewports](https://rv-grid.com/guide/viewports)
- [RevoGrid Pivot](https://rv-grid.com/pivot/)
- [RevoGrid Gantt](https://rv-grid.com/gantt/)
---
# Data Grid Width/Height
Source: https://rv-grid.com/guide/grid.size
# Data Grid Width/Height
Working with other data grid systems you probably looking for a way to setup width or height for grid viewport.
Good news it'll be updated automatically. All you have todo just change size of your table with css.
Be aware that there is a min-height of `300px` in the default data grid. It's just to avoid the grid to be too small.
---
# RevoGrid Best Practices
Source: https://rv-grid.com/guide/patterns
Description: Learn the practical patterns that keep RevoGrid fast and maintainable, including virtualization-safe renderers, state handling, editing flows, and large dataset strategies.
RevoGrid is designed for large datasets and interactive workflows, but the best results still come from using the right patterns. This guide focuses on practices that align with how the grid actually renders, edits, filters, and updates data.
## Treat virtualization as the default
The core grid renders only the visible rows and columns plus a small frame around them. Build with that assumption:
- keep custom cell renderers light
- avoid expensive DOM work per cell
- avoid doing data transforms inside every render callback
- prefer precomputed values on the row model when a template is reused many times
Read more in [Grid Performance and Virtualization](https://rv-grid.com/guide/performance).
## Separate source data from presentation concerns
Keep your source rows focused on business data, and use column config for presentation:
- `columns` define names, sorting, filters, templates, editors, and read-only rules
- `columnTypes` let you reuse configuration across many columns
- `rowDefinitions` are better than mutating row height logic into templates
- `additionalData` is useful for integration context, not as a second source of row data
## Prefer simple renderers first
Custom renderers are one of RevoGrid’s strengths, but the safest progression is:
1. plain column values
2. `cellProperties` for classes and attributes
3. `cellTemplate` for custom rendering
4. framework-native renderers only when the feature truly needs them
That keeps scroll performance predictable and makes debugging easier.
## Use stable keys in dynamic VNode output
When a renderer returns multiple nodes or list content, use stable keys based on your data model rather than array position. This helps the underlying VDOM reconcile updates correctly during filtering, sorting, and scrolling.
## Use methods for imperative workflows
If the UI needs to:
- focus a cell
- open an editor
- scroll to a row or column
- update a visible cell without rebuilding the whole grid
use the public methods instead of custom DOM hacks. Start with [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control).
## Keep event handling intentional
RevoGrid emits many events. In application code, it helps to group them by purpose:
- validation and write control: `beforeedit`, `beforerangeedit`, `beforeeditstart`
- source synchronization: `beforesourceset`, `aftersourceset`, `afteranysource`
- filtering and sorting pipelines: `beforefilterapply`, `beforefiltertrimmed`, `beforesorting`
- focus and selection: `beforecellfocus`, `beforefocuslost`, `afterfocus`
Use cancelable events to enforce business rules and informative events for analytics, syncing, or UI side effects.
Read more in [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide).
## Use physical and virtual indexes correctly
A common source of bugs is mixing physical source indexes with viewport indexes:
- source arrays are physical data
- event coordinates are often viewport-specific virtual indexes
- pinned rows and columns create separate index spaces
If you are using `setDataAt`, `setCellsFocus`, custom plugins, or advanced event handling, read [Understanding Viewports](https://rv-grid.com/guide/viewports).
## Choose the right loading strategy
For large or remote datasets:
- use built-in virtualization first
- use filtering and sorting carefully if the dataset must stay server-authoritative
- use incremental loading or pagination patterns when you do not want the full dataset in memory
- use `jobsBeforeRender` for initialization work that must finish before the first meaningful paint
For a complete remote data pattern with pagination, sorting, filtering, cancellation, caching, and optimistic edits, read [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data).
## Keep editing rules close to the column
Editing behavior is easiest to maintain when it is defined where the user sees it:
- `readonly` at grid or column level for broad rules
- custom editors in `editors`
- `applyOnClose` when you want close-to-save behavior
- validation in `beforeedit` or related hooks
Read more in [Editing](https://rv-grid.com/guide/editing).
## Make framework wrappers thin
Whether you use React, Angular, Vue 3, or Svelte, keep the wrapper layer focused on:
- providing props and events
- holding refs to the grid instance
- passing framework context through `additionalData` only when needed
The more business logic stays close to the shared RevoGrid API, the easier it is to keep behavior consistent across frameworks.
## Related guides
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Editing](https://rv-grid.com/guide/editing)
- [Filtering](https://rv-grid.com/guide/filters)
---
# RevoGrid Performance and Virtualization
Source: https://rv-grid.com/guide/performance
Description: Learn how RevoGrid keeps large datasets fast with virtual rendering, frame sizing, viewport settings, and initialization strategies such as jobsBeforeRender.
RevoGrid is designed to stay responsive with large datasets by rendering only what is needed. This guide explains the main performance-related props and when to use them.
## Virtual rendering is the default
The grid renders:
- visible rows and columns
- a small buffer outside the viewport
- pinned regions in coordinated viewports
This is why large datasets stay fast as long as cell templates and event handlers stay lightweight.
In practice, performance problems usually come from custom application code, not from the base grid itself. The most common causes are:
- expensive cell templates
- rebuilding `columns` too often
- pushing too much logic into per-cell render functions
- forcing full rerenders when a targeted update would be enough
## `frameSize`
`frameSize` defines how many extra rows and columns are rendered outside the visible area.
```ts
grid.frameSize = 1;
```
Use a higher value if:
- users scroll very quickly
- custom cells are visually expensive to mount
- you want a slightly larger pre-render buffer
Use a lower value if:
- you want to minimize off-screen rendering
- your templates are already cheap
Starting point:
- `1` is a good default for most apps
- increase it gradually if you see visible blanking during very fast scrolls
## `disableVirtualX`
`disableVirtualX` disables lazy rendering for columns.
```ts
grid.disableVirtualX = true;
```
This can help when:
- the grid has only a small number of columns
- you prefer stable DOM for horizontally visible cells
- initial rendering is more important than horizontal virtualization
Do not enable it by default for wide grids.
Example:
```ts
grid.disableVirtualX = grid.columns.length < 10;
```
## `disableVirtualY`
`disableVirtualY` disables lazy rendering for rows.
```ts
grid.disableVirtualY = true;
```
This is only appropriate when the row count is small enough that full vertical rendering is affordable.
Example:
```ts
grid.disableVirtualY = grid.source.length < 100;
```
## `jobsBeforeRender`
`jobsBeforeRender` lets you defer the first meaningful render until required async work is ready.
```ts
grid.jobsBeforeRender = [
fetch('/api/schema').then(r => r.json()),
fetch('/api/initial-grid-state').then(r => r.json()),
];
```
Good use cases:
- schema or permissions that must load before columns are built
- plugin bootstrapping that would otherwise cause immediate double rendering
- initial app state that must exist before the first visible grid
Typical setup:
```ts
const schemaJob = fetch('/api/columns').then(r => r.json());
const settingsJob = fetch('/api/grid-settings').then(r => r.json());
grid.jobsBeforeRender = [schemaJob, settingsJob];
```
## Renderer performance tips
- keep `cellTemplate` work small
- avoid network requests from inside renderers
- avoid rebuilding large arrays or objects on every cell render
- prefer data precomputation before assigning `source`
Bad pattern:
```ts
cellTemplate: () => {
const expensive = largeArray.filter(x => x.active);
return h('div', expensive.length);
}
```
Better pattern:
```ts
const activeCount = largeArray.filter(x => x.active).length;
cellTemplate: () => h('div', activeCount)
```
## Update methods for smoother UX
When you need to update a specific visible cell, `setDataAt` is often cheaper than rebuilding the entire grid state from scratch.
See [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control).
## Performance checklist
- use plain values before custom templates
- keep row data normalized before it reaches the grid
- prefer `setDataAt` for targeted updates
- use `getVisibleSource()` when operations only need the currently visible rows
- use server-side pagination, filtering, sorting, or grouping when the full dataset should not live in the browser
- leave virtualization enabled unless the dataset is genuinely small
## Related guides
- [Benchmarks](https://rv-grid.com/benchmarks)
- [Understanding Viewports](https://rv-grid.com/guide/viewports)
- [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data)
- [Best Practices](https://rv-grid.com/guide/patterns)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
---
# Programmatic Grid Control
Source: https://rv-grid.com/guide/programmatic-control
Description: Control RevoGrid from application code with public methods for editing, focus, scrolling, visible source access, and targeted cell updates.
RevoGrid exposes a rich public method surface for workflows driven by toolbars, external forms, keyboard shortcuts, or business logic.
## Get a grid instance
In plain JavaScript:
```ts
const grid = document.querySelector('revo-grid');
```
In framework wrappers, use the wrapper-specific ref or element access pattern, then call the underlying grid methods.
Example toolbar action:
```ts
const editFirstRowBtn = document.querySelector('#edit-first-row');
const grid = document.querySelector('revo-grid');
editFirstRowBtn?.addEventListener('click', async () => {
await grid?.scrollToRow(0);
await grid?.setCellEdit(0, 'name');
});
```
## Update one cell with `setDataAt`
Use `setDataAt` when you want to update a specific visible cell and refresh that cell without rebuilding the full grid.
```ts
await grid.setDataAt({
row: 0,
col: 0,
val: 'Updated',
});
```
Example with explicit viewport types:
```ts
await grid.setDataAt({
row: 0,
col: 0,
rowType: 'rowPinStart',
colType: 'rgCol',
val: 'Pinned row value',
});
```
Notes:
- `row` and `col` are virtual coordinates inside the selected viewport
- `rowType` defaults to `rgRow`
- `colType` defaults to `rgCol`
- `skipDataUpdate` can skip source mutation if you are only refreshing the rendered cell
## Open an editor with `setCellEdit`
```ts
await grid.setCellEdit(0, 'price');
```
This is useful when an external button or shortcut should put the user directly into editing mode.
Example with pinned rows:
```ts
await grid.setCellEdit(0, 'status', 'rowPinStart');
```
## Move focus with `setCellsFocus`
```ts
await grid.setCellsFocus({ x: 0, y: 0 }, { x: 2, y: 4 });
```
You can focus a single cell or a multi-cell range.
Focus a single cell before editing:
```ts
await grid.setCellsFocus({ x: 1, y: 3 }, { x: 1, y: 3 });
await grid.setCellEdit(3, 'price');
```
## Clear focus and inspect the current range
```ts
await grid.clearFocus();
const range = await grid.getSelectedRange();
console.log(range);
```
Typical pattern:
```ts
const range = await grid.getSelectedRange();
if (range) {
console.log('Selected area', range.x, range.y, range.x1, range.y1);
}
```
## Scroll to content
Scroll by row index:
```ts
await grid.scrollToRow(100);
```
Scroll by column index:
```ts
await grid.scrollToColumnIndex(5);
```
Scroll by column `prop`:
```ts
await grid.scrollToColumnProp('status');
```
This is usually safer than using column indexes when columns can be reordered or grouped.
## Read visible rows
```ts
const visibleRows = await grid.getVisibleSource();
```
Use this when your app should work with the rows currently visible after trimming, filtering, or sorting.
Example:
```ts
const visibleRows = await grid.getVisibleSource();
const selectedEmails = visibleRows.map(row => row.email);
console.log(selectedEmails);
```
## Read source and stores
```ts
const source = await grid.getSource();
const rowStore = await grid.getSourceStore();
const colStore = await grid.getColumnStore();
```
The store methods are mainly for advanced integrations and plugin work.
If you only need the current displayed rows, prefer `getVisibleSource()` over reading the raw store.
## Update sorting from application code
```ts
await grid.updateColumnSorting({ prop: 'name' }, 'asc', false);
await grid.clearSorting();
```
This emits the sorting configuration change rather than mutating the source directly.
Multi-step example:
```ts
await grid.updateColumnSorting({ prop: 'status' }, 'asc', false);
await grid.updateColumnSorting({ prop: 'createdAt' }, 'desc', true);
```
The second call keeps the first sort because `additive` is `true`.
## Plugin-oriented methods
These methods are most useful in advanced integrations:
- `getPlugins()`
- `getProviders()`
- `refreshExtraElements()`
They give access to active plugins and provider services used internally by the grid.
## Common patterns
### Build a “go to row” action
```ts
async function goToRow(rowIndex) {
await grid.scrollToRow(rowIndex);
await grid.setCellsFocus({ x: 0, y: rowIndex }, { x: 0, y: rowIndex });
}
```
### Refresh a visible cell after an external update
```ts
async function updateStatusCell(row, nextValue) {
await grid.setDataAt({
row,
col: 2,
val: nextValue,
});
}
```
### Read the filtered view before export or bulk action
```ts
const filteredRows = await grid.getVisibleSource();
console.log(`Exporting ${filteredRows.length} visible rows`);
```
## Related guides
- [Understanding Viewports](https://rv-grid.com/guide/viewports)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
---
# Proxy Source Editing
Source: https://rv-grid.com/guide/proxy-source
Description: Use JavaScript Proxy row models with RevoGrid so edits write through to an application-owned data store without edit event handlers.
RevoGrid reads and writes the row objects passed through `source`. During a normal edit, RevoGrid gets the row model for the visible row, assigns the edited value to `model[prop]`, and refreshes the source view.
You can use this behavior to make the application store the source of truth. Instead of listening to `beforeedit`, `beforerangeedit`, or `afteredit` for every write, pass RevoGrid an array of proxied row models. The proxy intercepts property reads and writes:
- `get` returns the value RevoGrid should render, sort, filter, group, or edit.
- `set` writes the new value into your application store.
- the same proxy row stays in `grid.source`, so RevoGrid keeps working with normal row objects.
Use edit events when you need grid-level cancellation, editor lifecycle control, analytics, or UI feedback. Use a proxy source when the main goal is to route cell writes into your own model.
## Basic Proxy Source
This example keeps `rawRows` as the application-owned data and passes a proxied array to RevoGrid.
```ts
type ProductRow = {
id: number;
name: string;
price: number;
status: 'draft' | 'published';
};
const rawRows: ProductRow[] = [
{ id: 1, name: 'Apple', price: 1.2, status: 'draft' },
{ id: 2, name: 'Banana', price: 0.5, status: 'published' },
];
function syncChange(row: ProductRow, prop: keyof ProductRow, value: unknown) {
console.log('row changed', row.id, prop, value);
}
function createRowProxy(
row: T,
onWrite: (row: T, prop: keyof T, value: unknown) => void,
): T {
return new Proxy(row, {
get(target, prop, receiver) {
return Reflect.get(target, prop, receiver);
},
set(target, prop, value) {
Reflect.set(target, prop, value);
onWrite(target, prop as keyof T, value);
return true;
},
});
}
const proxySource = rawRows.map(row => createRowProxy(row, syncChange));
const grid = document.querySelector('revo-grid');
if (grid) {
grid.columns = [
{ prop: 'id', name: 'ID', readonly: true },
{ prop: 'name', name: 'Name' },
{ prop: 'price', name: 'Price' },
{ prop: 'status', name: 'Status' },
];
grid.source = proxySource;
}
```
When a user edits the `price` cell, RevoGrid writes to the proxied row. The proxy updates `rawRows` and calls `syncChange`.
## External Store
A proxy source is useful when the grid-facing row shape is not the same as your store access pattern. This example stores rows by ID, tracks dirty fields, and queues asynchronous saves.
```ts
type InventoryRow = {
id: string;
sku: string;
quantity: number;
location: string;
};
const rowsById = new Map([
['a1', { id: 'a1', sku: 'A-001', quantity: 10, location: 'Lisbon' }],
['b2', { id: 'b2', sku: 'B-002', quantity: 25, location: 'Porto' }],
]);
const dirtyFields = new Map>();
const saveQueue: InventoryRow[] = [];
function markDirty(id: string, prop: keyof InventoryRow) {
const fields = dirtyFields.get(id) ?? new Set();
fields.add(prop);
dirtyFields.set(id, fields);
}
function queueSave(row: InventoryRow) {
saveQueue.push({ ...row });
}
function createStoreRowProxy(id: string): InventoryRow {
return new Proxy({ id } as InventoryRow, {
get(_, prop) {
return rowsById.get(id)?.[prop as keyof InventoryRow];
},
set(_, prop, value) {
const row = rowsById.get(id);
if (!row) {
return false;
}
(row as Record)[prop] = value;
markDirty(id, prop as keyof InventoryRow);
queueSave(row);
return true;
},
});
}
const proxySource = [...rowsById.keys()].map(createStoreRowProxy);
grid.source = proxySource;
grid.columns = [
{ prop: 'sku', name: 'SKU', readonly: true },
{ prop: 'quantity', name: 'Quantity' },
{ prop: 'location', name: 'Location' },
];
```
The proxy object exposes normal row properties to RevoGrid, but every read comes from `rowsById` and every write goes back into `rowsById`.
## Validation and Normalization
The `set` trap can normalize values before they reach your store.
```ts
function createValidatedRowProxy(row: ProductRow): ProductRow {
return new Proxy(row, {
set(target, prop, value) {
if (prop === 'name') {
target.name = String(value).trim();
return true;
}
if (prop === 'price') {
const price = Number(value);
if (!Number.isFinite(price) || price < 0) {
// Soft reject: keep the previous value and let the grid refresh it.
return true;
}
target.price = price;
return true;
}
Reflect.set(target, prop, value);
return true;
},
});
}
```
Returning `false` from a proxy `set` trap rejects the JavaScript assignment. In strict-mode code this can throw a `TypeError`, so a soft reject that preserves the previous value is usually easier for grid editing flows.
If the editor must be blocked before the value is committed, use `beforeedit` or `beforerangeedit` instead. Those events are still the correct place for hard cancellation and user-facing validation messages.
## Range Edits, Paste, and Programmatic Writes
Range edits and paste operations update row models by assigning values to the edited column properties. With a proxy source, those assignments still pass through the row proxy.
Programmatic writes use the same data path unless you explicitly skip data updates:
```ts
await grid.setDataAt({
row: 0,
col: 1,
val: 'Updated name',
});
```
If you call `setDataAt` with `skipDataUpdate: true`, RevoGrid updates the rendered cell only and does not assign the value into the row model.
```ts
await grid.setDataAt({
row: 0,
col: 1,
val: 'Temporary render value',
skipDataUpdate: true,
});
```
## Refresh Rules
If a grid edit writes through the proxy and the proxy returns the new value from the same row object, the normal edit flow updates the visible cell.
When the application store changes outside RevoGrid, refresh the grid so visible cells read the latest values from the proxies:
```ts
rowsById.get('a1')!.quantity = 12;
await grid.refresh();
```
If rows are added, removed, or reordered outside the grid, rebuild the proxied source array and assign it again:
```ts
const proxySource = [...rowsById.keys()].map(createStoreRowProxy);
grid.source = proxySource;
```
Pinned rows use separate sources, so prepare separate proxied arrays for them:
```ts
grid.pinnedTopSource = topRows.map(row => createRowProxy(row, syncChange));
grid.pinnedBottomSource = summaryRows.map(row =>
createRowProxy(row, syncChange),
);
```
## Practical Rules
- Keep proxy object identity stable where possible.
- Do not create proxies inside framework render loops. Build them in state setup, memoization, computed state, or a store adapter.
- Do not mutate the same field through both a proxy source and edit event handlers unless that duplication is intentional.
- Sorting, filtering, grouping, and cell rendering use values returned by the proxy `get` trap.
- Use `readonly`, `beforeedit`, and `beforerangeedit` for hard edit rules. Use proxy `set` for store synchronization and normalization.
## Related Guides
- [Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync)
- [Editing](https://rv-grid.com/guide/editing)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
---
# RevoGrid MCP for AI Agents
Source: https://rv-grid.com/guide/mcp
Description: Connect Codex, Cursor, Claude Code, and VS Code to the RevoGrid MCP server for version-aware docs, examples, migration notes, and typed API context.
RevoGrid MCP gives AI coding tools a structured way to work with RevoGrid instead of guessing from stale training data. It exposes version-aware documentation, runnable examples, migration notes, feature availability, and typed API context in a format that agents can query directly.
This is especially useful when you want an AI tool to:
- start from a working RevoGrid example instead of inventing setup code
- verify whether a feature exists in Core or Pro before suggesting it
- use current event names, options, and types such as `ColumnRegular` or `BeforeEdit`
- follow migration guidance between RevoGrid versions
## What the MCP server provides
The RevoGrid MCP server is read-only and focused on retrieval quality. It currently exposes:
- structured documentation search
- example search across frameworks
- feature matrix resolution for Core vs Pro support
- migration notes between versions
- typed API context derived from RevoGrid source
Agents can use this to retrieve:
- docs and guides
- live examples and demo sources
- feature availability
- migration records
- version metadata
- TypeScript-driven API symbols and configuration hints
## Why this works well with RevoGrid
RevoGrid already has strong typing and a source-driven API surface. That makes MCP especially effective here: the agent can ground its answers in real interfaces, events, and examples instead of relying on fuzzy pattern matching.
When you use RevoGrid with AI tools, the best results usually come from this order:
1. ask the agent to inspect RevoGrid MCP results first
2. ask it to use RevoGrid types as the source of truth
3. ask it to adapt the result to your framework and version
## Install in AI coding tools
Use the hosted RevoGrid MCP endpoint:
```text
https://mcp.rv-grid.com
```
### Claude Code
```bash
claude mcp add --transport http revogrid https://mcp.rv-grid.com
```
### Codex
```bash
codex mcp add revogrid --url https://mcp.rv-grid.com
```
### Cursor
Open MCP settings and add this entry to `.cursor/mcp.json`:
```json
{
"mcpServers": {
"RevoGrid": {
"url": "https://mcp.rv-grid.com",
"type": "http"
}
}
}
```
### VS Code
Open `MCP: Add Server...` and choose a remote HTTP MCP server, or add this to `.vscode/mcp.json`:
```json
{
"servers": {
"RevoGrid MCP": {
"url": "https://mcp.rv-grid.com",
"type": "http"
}
},
"inputs": []
}
```
## Prompt patterns that work well
These are good starting prompts for Codex, Cursor, Claude Code, VS Code MCP clients, or similar tools.
### Start from examples
- `Create an editable React RevoGrid using the best matching public examples and docs.`
- `Find the best Vue example for a custom column type and implement it.`
- `Show the Angular getting-started resources for RevoGrid and use the latest matching setup.`
### Ground work in types
- `Before writing code, look up the RevoGrid MCP docs and types for ColumnRegular, editors, and BeforeEdit.`
- `Use RevoGrid types as the source of truth for props, events, and plugin configuration.`
### Check features before implementing
- `Does RevoGrid support beforeedit in this version? Show docs, examples, and relevant types.`
- `Does pivot exist, and is it Core or Pro? If Pro is unavailable, recommend the closest public fallback.`
### Migrate safely
- `I am upgrading RevoGrid from 3.x to 4.x. Find migration notes, renamed symbols, and changed defaults that affect editing and events.`
## Recommended workflow for agents
If you are using an AI coding assistant on a RevoGrid codebase, ask it to:
1. search RevoGrid MCP before writing code
2. prefer public examples over free-form code generation
3. confirm Core vs Pro availability before suggesting a feature
4. check RevoGrid types when property names or event payloads matter
5. link back to the relevant docs or examples in the answer
This workflow tends to produce smaller, more accurate patches with fewer invented APIs.
## What to ask for explicitly
To get the highest-quality output from an agent, be specific about:
- framework: React, Vue, Angular, Svelte, or vanilla
- version: if you are pinned to a RevoGrid release line
- licensing: whether the solution must stay public/Core-only
- behavior: editing, pinning, grouping, virtualization, filtering, export, or plugins
For example:
```text
Create a Core-only React RevoGrid with editable cells and custom column types. Use RevoGrid MCP results first, prefer runnable examples, and validate the final config against RevoGrid types.
```
## Related pages
- [Quick Start](https://rv-grid.com/guide/)
- [Overview](https://rv-grid.com/guide/overview)
- [Examples](https://rv-grid.com/demo/)
- [Migration](https://rv-grid.com/guide/migration)
- [Typings](https://rv-grid.com/guide/types/README)
---
# RevoGrid Advanced Configuration
Source: https://rv-grid.com/guide/advanced-configuration
Description: Configure advanced RevoGrid props such as columnTypes, rowDefinitions, trimmedRows, additionalData, registerVNode, getProviders, and custom plugin hooks.
This guide covers public props and methods that are powerful, but usually only needed once your grid becomes part of a larger application architecture.
## `columnTypes`
`columnTypes` lets you define reusable column presets and reference them by name:
```ts
grid.columnTypes = {
readonlyText: {
readonly: true,
size: 180,
},
};
grid.columns = [
{ prop: 'name', name: 'Name', columnType: 'readonlyText' },
];
```
Use this when many columns share the same editor, renderer, read-only rule, or sizing rules.
More realistic example:
```ts
grid.columnTypes = {
money: {
size: 140,
readonly: false,
cellProperties: () => ({
class: {
'money-cell': true,
},
}),
},
lockedMeta: {
readonly: true,
size: 180,
},
};
grid.columns = [
{ prop: 'id', name: 'ID', columnType: 'lockedMeta' },
{ prop: 'total', name: 'Total', columnType: 'money' },
];
```
## `rowDefinitions`
`rowDefinitions` applies row-level configuration such as custom row size.
```ts
grid.rowDefinitions = [
{ type: 'rgRow', index: 0, size: 48 },
];
```
This is the right tool for row-specific layout changes instead of trying to force layout through cell templates alone.
Example with multiple row regions:
```ts
grid.rowDefinitions = [
{ type: 'rowPinStart', index: 0, size: 56 },
{ type: 'rgRow', index: 10, size: 44 },
];
```
## `trimmedRows` and `addTrimmed`
`trimmedRows` hides source rows from the main viewport by physical index:
```ts
grid.trimmedRows = {
2: true,
4: true,
};
```
For dynamic workflows, use:
```ts
await grid.addTrimmed({ 10: true, 11: true }, 'external');
```
Filtering uses trimming internally, but trimming is also useful for external rule-based visibility.
Typical use cases:
- hide archived rows without removing them from the source
- keep a temporary working subset visible
- combine application rules with filter-driven row visibility
## `additionalData`
`additionalData` passes contextual data into renderers, editors, and plugins.
```ts
grid.additionalData = {
currentUserRole: 'manager',
currency: 'EUR',
};
```
Use it for integration context, helper services, or framework-level references. Avoid turning it into a second source of truth for row data.
In renderers or editors, `additionalData` is often used for:
- current locale or currency
- permission flags
- external services
- framework context passed into custom templates
## `registerVNode`
`registerVNode` is for advanced cases where you want to register extra virtual nodes inside the grid, often from plugins.
```ts
grid.registerVNode = [
config => h('div', { class: 'my-extra-panel' }, 'Extra UI'),
];
```
This is not needed for normal application usage, but it is important for plugin-style extensions.
If the extra UI depends on application state, call `refreshExtraElements()` after updating the state so the registered VNodes can re-render.
## `getProviders()`
```ts
const providers = await grid.getProviders();
```
Providers expose access to grid services such as:
- data
- dimension
- selection
- column
- viewport
- plugin service
This is one of the key integration surfaces for plugin-oriented work.
Example:
```ts
const providers = await grid.getProviders();
const visibleMainRows = providers?.data.stores.rgRow.store.get('items');
console.log(visibleMainRows);
```
## `getPlugins()`
```ts
const plugins = await grid.getPlugins();
```
Use this when you need to inspect or coordinate active plugin instances from application code.
Example:
```ts
const plugins = await grid.getPlugins();
plugins.forEach(plugin => {
console.log(plugin.constructor.name);
});
```
## Other advanced props worth knowing
### `canFocus`
Disable focus rendering when the grid is used as a read-only viewer:
```ts
grid.canFocus = false;
```
### `useClipboard`
Disable built-in clipboard behavior when your app needs to fully own copy/paste:
```ts
grid.useClipboard = false;
```
### `stretch`
Control how columns fill remaining width:
```ts
grid.stretch = 'last';
```
### `accessible`
Keep accessibility enabled unless you have a very specific reason to disable it:
```ts
grid.accessible = true;
```
## Related guides
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [Plugin Guide](https://rv-grid.com/guide/plugin/)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
---
# RevoGrid Event Patterns and Lifecycles
Source: https://rv-grid.com/guide/events-guide
Description: Source-backed event lifecycle diagrams for RevoGrid, including root grid events, internal component chains, and plugin-driven flows such as editing, clipboard, sorting, filtering, focus, scrolling, and row ordering.
This page maps the event graph from the current source, not from assumptions.
Source priority used for this guide:
- [`src/components/revoGrid/revo-grid.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/revoGrid/revo-grid.tsx)
- [`src/components/overlay/revogr-overlay-selection.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/overlay/revogr-overlay-selection.tsx)
- [`src/components/clipboard/revogr-clipboard.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/clipboard/revogr-clipboard.tsx)
- [`src/plugins/sorting/sorting.plugin.ts`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/plugins/sorting/sorting.plugin.ts)
- [`src/plugins/filter/filter.plugin.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/plugins/filter/filter.plugin.tsx)
- [`src/components/header/revogr-header.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/header/revogr-header.tsx)
- [`src/components/selectionFocus/revogr-focus.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/selectionFocus/revogr-focus.tsx)
- [`src/components/editors/revogr-edit.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/editors/revogr-edit.tsx)
- [`src/components/order/revogr-order-editor.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/order/revogr-order-editor.tsx)
- [`src/components/data/revogr-data.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/data/revogr-data.tsx)
- [`src/components/scroll/revogr-viewport-scroll.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/scroll/revogr-viewport-scroll.tsx)
- [`src/types/events.ts`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/types/events.ts)
## How to read these diagrams
- `revo-grid` events are the public root lifecycle most app code listens to.
- Child-component events are often the trigger layer that `revo-grid` listens to and translates.
- Some plugin events are real but not part of the typed root `RevogridEvents` union.
- If a `before*` event is cancelable, the branch stops at that point.
## Event Layers
```mermaid
flowchart TB
A[User action or prop change] --> B[Child component event]
B --> C[revo-grid listener or watcher]
C --> D[Plugin reaction]
D --> E[Data or viewport mutation]
E --> F[After-event or render event]
```
## Root Grid Lifecycle
This is the outer lifecycle created by `componentWillLoad`, watchers, and render hooks.
```mermaid
flowchart TD
A[connectedCallback] --> B[created]
B --> C[componentWillLoad]
C --> D[themeChanged]
C --> E[columnChanged]
C --> F[dataSourceChanged source]
C --> G[dataSourceChanged pinnedTopSource]
C --> H[dataSourceChanged pinnedBottomSource]
C --> I[rowDefChanged]
C --> J[aftergridinit]
J --> K[componentWillRender]
K --> L[beforegridrender]
L --> M[render]
M --> N[componentDidRender]
N --> O[aftergridrender]
E --> E1[beforecolumnsset]
E1 --> E2[beforecolumnapplied]
E2 --> E3[aftercolumnsset]
F --> F1[beforesourceset]
F1 --> F2[beforeanysource]
F2 --> F3[aftersourceset]
F3 --> F4[afteranysource]
G --> G1[beforeanysource]
G1 --> G2[afteranysource]
H --> H1[beforeanysource]
H1 --> H2[afteranysource]
I --> I1[beforerowdefinition]
```
## Focus, Selection, and Edit Lifecycle
This flow starts in [`revogr-overlay-selection.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/overlay/revogr-overlay-selection.tsx) and is completed by `revo-grid` plus [`revogr-focus.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/selectionFocus/revogr-focus.tsx).
```mermaid
flowchart TD
A[Mouse down or keyboard navigation] --> B[beforecellfocusinit]
B --> C[revo-grid listens]
C --> D[beforecellfocus]
D --> E[applyfocus]
E --> F[focuscell]
F --> G[revogr-focus render]
G --> H[beforefocusrender]
H --> I[beforescrollintoview]
I --> J[afterfocus]
J --> K[revo-grid afterfocus duplicate]
F --> L[Double click or keypress starts edit]
L --> M[setedit]
M --> N[revo-grid onSetedit]
N --> O[beforeeditstart]
O --> P[selection store edit state]
P --> Q[beforeeditrender]
Q --> R[revogr-edit mounted]
R --> S[celleditinit or closeedit]
S --> T[celledit]
T --> U[beforecellsave]
U --> V[celleditapply]
V --> W[revo-grid beforeedit]
W --> X[dataProvider.setCellData]
X --> Y[afteredit]
S --> Z[closeedit]
Z --> AA[canceledit]
```
### Edit commit notes
- `beforeeditstart` blocks opening the editor.
- `beforecellsave` blocks the overlay from forwarding the save.
- `beforeedit` blocks the root data write.
- `afteredit` fires after single-cell and range writes.
## Range, Autofill, and Clipboard Lifecycle
The range flow is handled in the overlay and clipboard components, then translated into root edit events by `revo-grid`.
```mermaid
flowchart TD
A[Shift+focus drag or autofill drag] --> B[beforeapplyrange]
B --> C[beforesetrange]
C --> D[setrange]
D --> E[Range visible in overlay]
E --> F[Autofill handle or range apply]
F --> G[selectionchangeinit]
G --> H[revo-grid beforerange]
H --> I[revo-grid beforeautofill]
I --> J[beforerangedataapply]
J --> K[beforesettemprange]
K --> L[settemprange]
L --> M[beforerangecopyapply]
M --> N[rangeeditapply]
N --> O[revo-grid beforerangeedit]
O --> P[dataProvider.setRangeData]
P --> Q[afteredit]
```
### Clipboard copy/cut
```mermaid
flowchart TD
A[Document copy] --> B[beforecopy]
B --> C[copyregion]
C --> D[overlay beforecopyregion]
D --> E[clipboardrangecopy]
E --> F[beforecopyapply]
F --> G[clipboard text written]
H[Document cut] --> I[beforecut]
I --> J[copy path runs]
J --> K[clearregion]
K --> L[overlay clearCell or range clear]
L --> M[celleditapply or rangeeditapply]
M --> N[beforeedit or beforerangeedit]
N --> O[afteredit]
```
### Clipboard paste
```mermaid
flowchart TD
A[Document paste] --> B[beforepaste]
B --> C[beforepasteapply]
C --> D[pasteregion]
D --> E[overlay clipboardrangepaste]
E --> F[autofill service onRangeApply]
F --> G[selectionchangeinit]
G --> H[beforerange]
H --> I[beforeautofill]
I --> J[rangeeditapply]
J --> K[beforerangeedit]
K --> L[afteredit]
D --> M[afterpasteapply]
```
## Header, Sorting, and Filtering Lifecycle
Header events start in [`revogr-header.tsx`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/components/header/revogr-header.tsx). Sorting and filtering then hook into those events.
```mermaid
flowchart TD
A[Header render] --> B[beforeheaderrender]
B --> C[beforegroupheaderrender]
C --> D[afterheaderrender]
E[Header click] --> F[beforeheaderclick]
F --> G[revo-grid headerclick]
G --> H[SortingPlugin or FilterPlugin]
I[Header resize gesture] --> J[beforeheaderresize]
J --> K[headerresize]
K --> L[viewport resize service]
L --> M[aftercolumnresize]
```
### Sorting
```mermaid
flowchart TD
A[beforeheaderclick on sortable column] --> B[SortingPlugin headerclick]
B --> C[beforesorting]
C --> D[beforesortingapply]
D --> E[sorting state updated in plugin]
E --> F[startSorting]
F --> G[sort data stores]
G --> H[aftersortingapply]
G --> I[source watchers may later re-trigger beforeanysource]
J[beforeanysource] --> K[SortingPlugin beforesourcesortingapply]
K --> L[startSorting]
L --> G
M[sorting prop change or updateColumnSorting] --> N[sortingconfigchanged]
N --> O[SortingPlugin config update]
O --> F
```
### Filtering
```mermaid
flowchart TD
A[headerclick on filter button] --> B[FilterPlugin opens panel]
B --> C[filterChange or resetChange]
C --> D[runFiltering]
D --> E[beforefilterapply]
E --> F[getRowFilter]
F --> G[beforefiltertrimmed]
G --> H[dataProvider.setTrimmed filter]
H --> I[afterfilterapply]
H --> J[revo-grid beforetrimmed if trimmedRows API used]
H --> K[Grid render with filtered rows]
L[filter prop change] --> M[filterconfigchanged]
M --> D
N[aftersourceset] --> O[FilterPlugin reruns active filters]
O --> D
```
## Row Ordering Lifecycle
```mermaid
flowchart TD
A[dragstartcell] --> B[revogr-order-editor dragStart]
B --> C[rowdragstartinit]
C --> D[revo-grid rowdragstart]
D --> E[orderService.start]
E --> F[rowdragmoveinit]
F --> G[rowdragmousemove]
G --> H[rowdropinit]
H --> I[revo-grid roworderchanged]
I --> J[roworderchange]
J --> K[dataProvider.changeOrder]
K --> L[rowdragendinit]
```
## Scroll and Data Render Lifecycle
```mermaid
flowchart TD
A[Viewport resize] --> B[resizeviewport]
B --> C[dimension provider updates]
C --> D[contentsizechanged]
E[Viewport scroll] --> F[scrollviewport]
F --> G[GridScrollingService]
G --> H[viewportscroll]
F --> I[scrollchange]
F --> J[scrollviewportsilent]
K[Data component will render] --> L[beforedatarender]
L --> M[beforerowrender]
M --> N[beforecellrender]
N --> O[afterrender]
```
## Source and Config Watchers
These are not user gestures. They are reactive lifecycle edges triggered by prop updates.
```mermaid
flowchart TD
A[source change] --> B[beforesourceset]
B --> C[beforeanysource]
C --> D[aftersourceset]
D --> E[afteranysource]
F[columns change] --> G[beforecolumnsset]
G --> H[beforecolumnapplied]
H --> I[aftercolumnsset]
J[theme change] --> K[afterthemechanged]
L[rowDefinitions change] --> M[beforerowdefinition]
N[trimmedRows change] --> O[beforetrimmed]
O --> P[aftertrimmed]
Q[sorting change] --> R[sortingconfigchanged]
S[filter change] --> T[filterconfigchanged]
U[rowHeaders change] --> V[rowheaderschanged]
W[additionalData change] --> X[additionaldatachanged]
```
## Public vs Internal Event Surface
Use [`src/types/events.ts`](https://rv-grid.com/Users/maks/Projects/revogrid-pro-advance/revogrid/src/types/events.ts) as the typed public event catalog.
Most application integrations should anchor on:
- `created`, `aftergridinit`, `beforegridrender`, `aftergridrender`
- `beforesourceset`, `beforeanysource`, `aftersourceset`, `afteranysource`
- `beforecolumnsset`, `beforecolumnapplied`, `aftercolumnsset`
- `beforeeditstart`, `beforeedit`, `beforerangeedit`, `afteredit`
- `beforecellfocus`, `beforefocuslost`, `afterfocus`
- `beforerange`, `beforeautofill`
- `beforesorting`, `beforesortingapply`, `beforesourcesortingapply`, `sortingconfigchanged`
- `beforefilterapply`, `beforefiltertrimmed`, `beforetrimmed`, `aftertrimmed`
- `rowdragstart`, `roworderchanged`
- `viewportscroll`, `contentsizechanged`, `aftercolumnresize`
Useful internal or plugin-only events that also appear in flows:
- `beforeapplyrange`, `beforesetrange`, `setrange`
- `beforepaste`, `beforepasteapply`, `pasteregion`, `afterpasteapply`
- `beforecopyregion`, `clipboardrangecopy`, `clipboardrangepaste`
- `beforefocusrender`, `beforescrollintoview`
- `beforeheaderclick`, `beforeheaderrender`, `beforegroupheaderrender`
- `aftersortingapply`, `afterfilterapply`, `newRows`, `rtlstatechanged`
## Recommended Hooks by Use Case
### Validate edits before commit
- `beforeedit`
- `beforerangeedit`
- `beforecellsave` if you need to stop the overlay before the root write
### Persist changes after commit
- `afteredit`
- `aftersourceset` if you replace source externally
### Drive custom navigation
- `beforecellfocus`
- `beforefocuslost`
- `beforenextvpfocus`
- `afterfocus`
### Observe filter and sorting transitions
- `beforefilterapply`
- `beforefiltertrimmed`
- `beforesorting`
- `beforesortingapply`
- `beforesourcesortingapply`
- `sortingconfigchanged`
### Track render and viewport changes
- `beforegridrender`
- `aftergridrender`
- `beforedatarender`
- `afterrender`
- `viewportscroll`
- `contentsizechanged`
## Related guides
- [Editing](https://rv-grid.com/guide/editing)
- [Filtering](https://rv-grid.com/guide/filters)
- [Sorting](https://rv-grid.com/guide/sorting)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [API: Events](https://rv-grid.com/guide/api/events)
---
# TSX Template
Source: https://rv-grid.com/guide/jsx.template
# JSX/TSX - Custom Content Rendering
JSX (or TSX if you're using TypeScript) is a syntax extension to JavaScript that simplifies template rendering. We highly recommend using JSX/TSX as it will make your development process much easier.
```jsx
const MyTemplate = (h, column) =>
{ column.name }
```
While JSX is commonly associated with React, it is not exclusive to it. JSX is simply a way to render content and can be used in any project you choose. We use JSX/TSX in all our projects because it simplifies the rendering process.
For example, consider a regular column header rendered with `createElement`:
```js
const columnTemplate = (createElement, column) => {
return createElement('span', {
style: {
color: 'red'
},
}, createElement('div', {
class: 'me'
}, column.name));
};
const columns = [{
name: 'Person name',
prop: 'name',
columnTemplate
}];
```
Now imagine having 10 or more child nodes. This can quickly become complex. Let's simplify it with JSX or TSX.
> [!WARNING]
> Remember to escape any HTML code to prevent XSS attacks.
First, create a myJsx.jsx file:
```jsx
export const myTemplate = (h, column) => {
return
{column.name}
;
}
```
Then in our main file:
```js
import { myTemplate } from `./myJsx`;
const columns = [{
name: 'Person name',
prop: 'name',
columnTemplate: myTemplate
}];
```
Quite simple, right?
## Using Keys in JSX Templates
> [!IMPORTANT]
> **Keys are essential for VNode reconciliation.** When rendering lists or dynamic content, always provide unique keys to help the virtual DOM accurately identify, track, and update nodes. Use keys thoughtfully, as incorrect usage can lead to inefficient updates or unexpected behavior.
Keys allow the virtual DOM to:
- **Identify unique nodes** - Distinguish between different items even when content is similar
- **Optimize updates** - Efficiently update only the nodes that have changed
- **Preserve state** - Maintain component state when items are reordered or filtered
### Basic Key Usage
When rendering multiple elements, always provide a unique `key` prop:
```jsx
const MyTemplate = (h, props) => {
const items = props.model.items || [];
return (
{items.map((item, index) => (
{item.name}
))}
);
}
```
### Best Practices for Keys
1. **Use stable, unique identifiers** - Prefer IDs from your data over array indices:
```jsx
// ✅ Good - uses stable ID
{items.map(item => (
{item.name}
))}
// ⚠️ Acceptable - uses index when no ID available
{items.map((item, index) => (
{item.name}
))}
```
2. **Combine identifiers for uniqueness** - When rendering cells, combine row and column identifiers:
```jsx
const CellTemplate = (h, props) => {
return (
{props.model[props.prop]}
);
}
```
3. **Avoid changing keys** - Keys should remain stable for the same item across renders:
```jsx
// ❌ Bad - key changes on every render
);
}
```
## TypeScript JSX Cell Template Demo
[Check out this sample.](https://codesandbox.io/s/revo-grid-vanilla-jsx-zj0q6?file=/src/index.js)
We use babel-jsx with minimal configuration settings.
---
# RevoGrid Features and Definitions
Source: https://rv-grid.com/guide/defs
Description: A practical glossary for RevoGrid concepts, including cells, columns, rows, ranges, viewports, plugins, props, methods, and virtual scrolling.
This page is a quick glossary for the concepts used throughout the RevoGrid docs. It is especially useful when you are moving between high-level guides, framework wrappers, and the API reference.
## Lifecycle Hooks
For detailed interactions and operations, RevoGrid provides a variety of [events](https://rv-grid.com/guide/api/revoGrid#Events) that function similarly to lifecycle hooks, allowing developers to listen and respond to different stages and actions within the grid's lifecycle.
Here's a brief overview of some key events which can help in managing grid behavior, data manipulation, and user interactions:
### Source
- **`beforeanysource`**: Triggered before data application in [`data source`](https://rv-grid.com/guide/defs#Data-Source).
- **`afteranysource`**: Fires after all rows are updated.
- **`beforesourceset`**: Fired before [`data source`](https://rv-grid.com/guide/defs#Data-Source) application.
- **`aftersourceset`**: Occurs after rows are updated.
- **`beforetrimmed`**: Triggered before [`trimmed rows`](https://rv-grid.com/guide/defs#Trimmed-Rows) are applied.
- **`aftertrimmed`**: Notifies when [`trimmed rows`](https://rv-grid.com/guide/defs#Trimmed-Rows) is applied.
### Column
- **`beforecolumnapplied`**: Happens before columns are applied.
- **`beforecolumnsset`**: Triggered before column updates.
- **`aftercolumnsset`**: Fired when columns are updated.
### Edit
- **`beforeedit`**: Triggered before an edit is applied.
- **`beforerangeedit`**: Occurs before a range edit is applied.
- **`beforeautofill`**: Fired before autofill operation.
- **`afteredit`**: Executes after an edit action is completed.
### Focus/Selection
- **`beforecellfocus`**: Occurs before cell focus changes.
- **`beforefocuslost`**: Happens before grid focus is lost.
- **`afterfocus`**: Fires after focus render is completed.
Events provide a structured approach to handling RevoGrid's functionalities, making it easier to implement and manage complex data grid behaviors in web applications.
## API
The public API is the combination of:
- props such as `columns`, `source`, `filter`, `grouping`, and `additionalData`
- methods such as `setDataAt`, `scrollToRow`, `setCellsFocus`, and `getVisibleSource`
- events such as `beforeedit`, `afteredit`, `beforefilterapply`, and `beforesourceset`
Start at [RevoGrid API](https://rv-grid.com/guide/api/revoGrid).
## Cell
The intersection point of a row and a column in the grid, capable of displaying and editing data. A cell can have custom renderers and editors, which are tightly coupled with the column properties.
You can [customize cells using templates](https://rv-grid.com/guide/cell/renderer) to change their appearance or behavior.
### Cell editor
A cell editor is the UI used to modify a value. RevoGrid ships with a core editor flow and supports custom editor registration through the `editors` prop.
### Cell template
A cell template is a custom renderer for displaying richer cell content while keeping the grid virtualized.
### Cell merge
Cell merging refers to combining adjacent cells into a larger visual area. This is available in RevoGrid Pro.
## Clipboard
Clipboard support enables copy, cut, and paste workflows. It is controlled by `useClipboard` and range selection behavior. See [Clipboard Operations](https://rv-grid.com/guide/clipboard).
## Column
Columns define how the grid reads and displays row data. A column can configure:
- `prop` mapping
- `name`
- `size`, `minSize`, `maxSize`
- `sortable`
- `filter`
- `editor`
- `cellTemplate`
- `cellProperties`
- `readonly`
- `pin`
- `columnType`
Related guides:
- [Column Definitions](https://rv-grid.com/guide/column/)
- [Custom Columns](https://rv-grid.com/guide/column/types)
- [Column Groups](https://rv-grid.com/guide/column/grouping)
## Data source
The data source is the row array shown by the grid. The main dataset is assigned through `source`, while pinned row regions use `pinnedTopSource` and `pinnedBottomSource`.
## Data model
The data model is the shape of each row object inside your source array.
```typescript
interface Person {
id: number;
name: string;
age: number;
email: string;
}
```
## Event
Events are how RevoGrid exposes lifecycle and interaction hooks. Many events are cancelable and let you change the behavior before the grid commits it.
Examples:
- editing: `beforeedit`, `afteredit`
- data updates: `beforesourceset`, `aftersourceset`
- filtering: `beforefilterapply`, `beforefiltertrimmed`
- focus: `beforecellfocus`, `beforefocuslost`, `afterfocus`
See [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide) and [Hooks and Events API](https://rv-grid.com/guide/api/events).
## Export
The core export plugin supports CSV file export workflows from the grid surface. See [Export Data](https://rv-grid.com/guide/export.plugin). Excel-focused export workflows are available in Pro, and browser-side PDF export is available through the [`@revolist/revogrid-pdf-export`](https://rv-grid.com/guide/pdf-export) add-on plugin.
## Focus
Focus is the active cell target used for keyboard navigation, editing, and selection overlays. It can be enabled or disabled with `canFocus`.
Useful methods:
- `setCellsFocus`
- `clearFocus`
- `getFocused`
## Range
A range is a rectangular selection of cells. Range selection is enabled with the `range` prop and exposed through `getSelectedRange`.
### Range autofill
Autofill extends a selected value or pattern across a dragged range. Advanced autofill workflows are available in RevoGrid Pro.
## Keyboard support
RevoGrid includes keyboard navigation for moving focus, editing cells, selecting ranges, and copying or pasting data. Custom features should integrate with keyboard behavior rather than bypassing it.
## Method
Methods are imperative APIs exposed on the grid instance. They are useful when application state or external controls need to drive the grid directly.
Examples:
- `scrollToRow`
- `scrollToColumnProp`
- `setCellEdit`
- `setDataAt`
- `getVisibleSource`
## Plugin
Plugins extend grid behavior without changing the core component. RevoGrid includes built-in plugins for filtering, sorting, exporting, grouping, stretching, accessibility, and more.
The `plugins` prop can also receive custom plugin classes. For plugin-oriented props and provider access, see [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration).
### Filtering
The filtering plugin hides rows that do not match the selected criteria.
### Sorting
The sorting plugin updates column order state and applies sorted row order to the source.
### Pagination
Pagination is not part of the OSS core guide surface today. It is available through RevoGrid Pro workflows.
## Performance
Performance in RevoGrid comes from virtual rendering, viewport separation, lightweight renderers, and explicit data update methods. Read [Grid Performance and Virtualization](https://rv-grid.com/guide/performance).
## Prop
A prop is a public configuration field passed to the grid, such as `columns`, `source`, `filter`, `readonly`, `stretch`, or `grouping`.
## Row
Rows represent records in the source dataset and can be customized through pinned regions, row headers, row definitions, grouping, and trimming.
### Row grouping
Row grouping groups records under shared labels based on selected props. See [Row Grouping](https://rv-grid.com/guide/row/grouping).
### Row headers
Row headers add an index or custom left-hand row area. See [Row Headers](https://rv-grid.com/guide/row/headers).
### Row pinning
Pinned rows stay visible in `pinnedTopSource` or `pinnedBottomSource` while the main dataset scrolls.
### Trimmed rows
Trimmed rows are source rows that exist but are currently hidden from the visible viewport. Filtering uses trimming internally, and you can also control trimming directly with `trimmedRows` or `addTrimmed`.
## Viewport
A viewport is one rendered region of the grid. RevoGrid uses separate viewports for:
- main rows: `rgRow`
- pinned top rows: `rowPinStart`
- pinned bottom rows: `rowPinEnd`
- main columns: `rgCol`
- pinned start columns: `colPinStart`
- pinned end columns: `colPinEnd`
Events often expose indexes relative to a viewport, not the original array position. See [Understanding Viewports](https://rv-grid.com/guide/viewports).
### Virtual scrolling
Virtual scrolling means the grid renders only what is visible, plus a small rendering frame. This keeps large grids usable and responsive.
## VNode Reactive DOM
At the core of RevoGrid's high performance is its use of a reactive DOM model (similar one you would find in any popular reactive framework [Vue Virtual DOM](https://vuejs.org/guide/extras/rendering-mechanism), [React Virtual DOM](https://legacy.reactjs.org/docs/faq-internals.html), etc.). This model ensures that only the parts of the grid that need updating are re-rendered, rather than the entire grid. This selective rendering mechanism is crucial for handling large amounts of data, as it significantly reduces the amount of DOM manipulation required, leading to smoother scrolling and interactions.
## Web Component
RevoGrid is implemented as a Web Component, which is why it can be used directly in JavaScript and wrapped by multiple frameworks without changing the core implementation.
## Related guides
- [Overview](https://rv-grid.com/guide/overview)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
---
# API
Source: https://rv-grid.com/guide/api/revoGrid
## Overview
Revogrid - High-performance, customizable grid library for managing large datasets.
### Events guide
For a comprehensive events guide, check the [Events API Page](https://rv-grid.com/guide/api/events).
All events propagate to the root level of the grid. [Dependency tree](#Dependencies).
### Type definitions
Read [type definition file](https://github.com/revolist/revogrid/blob/master/src/interfaces.d.ts) for the full interface information.
All complex property types such as `ColumnRegular`, `ColumnProp`, `ColumnDataSchemaModel` can be found there.
### HTMLRevoGridElement
## Properties
| Property | Attribute | Description | Type | Default |
| ---------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `accessible` | `accessible` | Enable accessibility. If disabled, the grid will not be accessible. | `boolean` | `true` |
| `additionalData` | -- | Additional data to be passed to plugins, renders or editors. For example if you need to pass Vue component instance. | `AdditionalData` | `{}` |
| `applyOnClose` | `apply-on-close` | Apply changes in editor when closed except 'Escape' cases. If custom editor in use method getValue required. Check interfaces.d.ts `EditorBase` for more info. | `boolean` | `false` |
| `autoSizeColumn` | `auto-size-column` | Autosize config. Enables columns autoSize. For more details check `autoSizeColumn` plugin. By default disabled, hence operation is not performance efficient. `true` to enable with default params (double header separator click for autosize). Or define config. See `AutoSizeColumnConfig` for more details. | `boolean \| { mode?: ColumnAutoSizeMode \| undefined; allColumns?: boolean \| undefined; letterBlockSize?: number \| undefined; preciseSize?: boolean \| undefined; }` | `false` |
| `canDrag` | `can-drag` | Disable native drag&drop plugin. | `boolean` | `true` |
| `canFocus` | `can-focus` | When true cell focus appear. | `boolean` | `true` |
| `canMoveColumns` | `can-move-columns` | Enable column move plugin. | `boolean` | `true` |
| `colSize` | `col-size` | Indicates default column size. | `number` | `100` |
| `columnTypes` | -- | Column Types Format. Every type represent multiple column properties. Types will be merged but can be replaced with column properties. Types were made as separate objects to be reusable per multiple columns. | `{ [name: string]: ColumnType>; }` | `{}` |
| `columns` | -- | Columns - defines an array of grid columns. Can be column or grouped column. | `(ColumnRegular> \| ColumnGrouping)[]` | `[]` |
| `disableVirtualX` | `disable-virtual-x` | Disable lazy rendering mode for the `X axis`. Use when not many columns present and you don't need rerenader cells during scroll. Can be used for initial rendering performance improvement. | `boolean` | `false` |
| `disableVirtualY` | `disable-virtual-y` | Disable lazy rendering mode for the `Y axis`. Use when not many rows present and you don't need rerenader cells during scroll. Can be used for initial rendering performance improvement. | `boolean` | `false` |
| `editors` | -- | Custom editors register. | `{ [name: string]: EditorCtr; }` | `{}` |
| `exporting` | `exporting` | Enable export plugin. | `boolean` | `true` |
| `filter` | `filter` | Enables filter plugin. Enabled by default; set to `false` to opt out. Can be boolean. Or can be filter collection See `FilterCollection` for more info. | `ColumnFilterConfig \| boolean` | `true` |
| `focusTemplate` | -- | Apply changes typed in editor on editor close except Escape cases. If custom editor in use method `getValue` required. Check `interfaces.d.ts` `EditorBase` for more info. | `(createElement: HyperFunc, detail: FocusRenderEvent) => any` | `undefined` |
| `frameSize` | `frame-size` | Defines how many rows/columns should be rendered outside visible area. | `number` | `1` |
| `grouping` | -- | Group rows based on this property. Define properties to be groped by grouping plugin See `GroupingOptions`. | `{ props?: ColumnProp[] \| undefined; preserveGroupingOnUpdate?: boolean \| undefined; groupLabelTemplate?: GroupLabelTemplateFunc \| undefined; groupCellTemplate?: GroupCellTemplateFunc \| undefined; } & ExpandedOptions` | `undefined` |
| `hideAttribution` | `hide-attribution` | Please only hide the attribution if you are subscribed to Pro version | `boolean` | `false` |
| `jobsBeforeRender` | -- | Prevent rendering until job is done. Can be used for initial rendering performance improvement. When several plugins require initial rendering this will prevent double initial rendering. | `Promise[]` | `[]` |
| `noHorizontalScrollTransfer` | `no-horizontal-scroll-transfer` | Prevents horizontal scroll state from being mirrored across viewport sections. | `boolean` | `false` |
| `pinnedBottomSource` | -- | Pinned bottom Source: {[T in ColumnProp]: any} - defines pinned bottom rows data source. | `DataType[]` | `[]` |
| `pinnedTopSource` | -- | Pinned top Source: {[T in ColumnProp]: any} - defines pinned top rows data source. | `DataType[]` | `[]` |
| `plugins` | -- | Custom grid plugins. Can be added or removed at runtime. Every plugin should be inherited from BasePlugin class. For more details check [Plugin guide](https://rv-grid.com/guide/plugin/) | `(typeof BasePlugin)[]` | `[]` |
| `range` | `range` | When true, user can select a cell range. Required for range-based clipboard fill. | `boolean` | `false` |
| `readonly` | `readonly` | When true, grid in read only mode. | `boolean` | `false` |
| `registerVNode` | -- | Register new virtual node inside of grid. Used for additional items creation such as plugin elements. Should be set before grid render inside of plugins. Can return VNode result of h() function or a function that returns VNode. Function can be used for performance improvement and additional renders. | `(VNode \| ((c: ExtraNodeFuncConfig) => VNode))[]` | `[]` |
| `resize` | `resize` | When true, columns are resizable. | `boolean` | `true` |
| `resizeRow` | `resize-row` | Enables row resizing. Pass a configuration object to customize the height limits or enable resize edges across the full row. | `boolean \| { minHeight?: number \| undefined; maxHeight?: number \| undefined; fullRow?: boolean \| undefined; }` | `false` |
| `rowClass` | `row-class` | Row class property mapping. Map custom classes to rows from row object data. Define this property in rgRow object and this will be mapped as rgRow class. | `string` | `''` |
| `rowDefinitions` | -- | Custom row properies to be applied. See `RowDefinition` for more info. | `RowDefinition[]` | `[]` |
| `rowHeaders` | `row-headers` | Excel like functionality. Show row numbers. Also can be used for custom row header render if object provided. | `RowHeaders \| boolean` | `undefined` |
| `rowSize` | `row-size` | Indicates default rgRow size. By default 0, means theme package size will be applied Alternatively you can use `rowSize` to reset viewport | `number` | `0` |
| `rtl` | `rtl` | Enable right-to-left (RTL) mode. When enabled, columns will be displayed from right to left. | `boolean` | `false` |
| `sorting` | -- | Alternative way to set sorting. `{columns: [{prop: 'name', order: 'asc'}]}` Use SortingPlugin to get current sorting state | `undefined \| { columns?: { prop: ColumnProp; order: Order; cellCompare?: CellCompareFunc \| undefined; }[] \| undefined; additive?: boolean \| undefined; }` | `undefined` |
| `source` | -- | Source - defines main data source. Can be an Object or 2 dimensional array([][]); Keys/indexes referenced from columns Prop. | `DataType[]` | `[]` |
| `stretch` | `stretch` | Stretch strategy for columns by `StretchColumn` plugin. For example if there are more space on the right last column size would be increased. | `boolean \| string` | `false` |
| `theme` | `theme` | Theme name. | `string` | `'default'` |
| `themeDefinitions` | -- | Per-grid custom theme definitions. Assign as a JavaScript property; complex values cannot be serialized as HTML attributes. | `ThemeDefinition[]` | `[]` |
| `trimmedRows` | -- | Trimmed rows. Functionality which allows to hide rows from main data set. `trimmedRows` are physical `rgRow` indexes to hide. | `boolean \| number` | `{}` |
| `useClipboard` | `use-clipboard` | When true enable clipboard. Can be boolean or clipboard config. | `ClipboardConfig \| boolean` | `true` |
| `virtualX` | -- | Column dimensions that use X axis virtual rendering. Defaults to regular columns only to preserve pinned column behavior. Set to `['rgCol', 'colPinStart', 'colPinEnd']` to virtualize all column areas. | `DimensionCols[]` | `['rgCol']` |
## Events
| Event | Description | Type |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `additionaldatachanged` | Emmited after the additional data is changed | `CustomEvent` |
| `afteranysource` | Emitted after each source update, whether from the pinned or main viewport. Useful for tracking all changes originating from sources in both the pinned and main viewports. | `CustomEvent<{ type: DimensionRows; source: DataType[]; }>` |
| `aftercolumnresize` | Emitted after column resizing. Useful for retrieving the resized columns. | `CustomEvent<{ [index: number]: ColumnRegular>; }>` |
| `aftercolumnsset` | Column updated | `CustomEvent<{ columns: ColumnCollection; order: SortingOrder; }>` |
| `afteredit` | After data applied or range changed. | `CustomEvent>> \| D \| K>` |
| `afterfocus` | After focus render finished. Can be used to access a focus element through `event.target`. This is just a duplicate of `afterfocus` from `revogr-focus.tsx`. | `CustomEvent>>` |
| `aftergridinit` | Emmited after the grid is initialized. Connected to the DOM. | `CustomEvent` |
| `aftergridrender` | Emmited after the grid is rendered. | `CustomEvent` |
| `aftersortingapply` | By `SortingPlugin` Triggered after sorting has been applied and completed. Provides final sorting state and sorting column metadata when available. | `CustomEvent<{ sorting?: SortingOrder \| undefined; sortingColumns?: SortingColumnMap \| undefined; sortingOrder?: SortingColumnOrder \| undefined; types: DimensionRows[]; }>` |
| `aftersourceset` | After main source/rows updated | `CustomEvent<{ type: DimensionRows; source: DataType[]; }>` |
| `afterthemechanged` | Emmited after the theme is changed | `CustomEvent` |
| `aftertrimmed` | Emitted after trimmed values have been applied. Useful for notifying when trimming of values has taken place. | `CustomEvent` |
| `beforeanysource` | Before data apply on any source type. Can be source from pinned and main viewport. You can override data source here | `CustomEvent<{ type: DimensionRows; source: DataType[]; }>` |
| `beforeautofill` | Before autofill is applied. To prevent the default behavior of applying the edit data, you can call `e.preventDefault()`. | `CustomEvent<{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }>` |
| `beforecellfocus` | Before the cell focus is changed. To prevent the default behavior of changing the cell focus, you can call `e.preventDefault()`. | `CustomEvent>>>` |
| `beforecolumnapplied` | Emitted before a column update is applied, after the column set is gathered and the viewport is updated. Useful for performing actions or modifications before the final application of the column update. | `CustomEvent<{ columns: Record>[]>; columnByProp: Record>[]>; columnGrouping: ColumnGroupingCollection; maxLevel: number; sort: Record>>; }>` |
| `beforecolumnsgather` | Emitted before user column definitions are gathered into the internal column collection. Listeners can replace `detail.columns` to rewrite the raw column set before RevoGrid normalizes it. | `CustomEvent<{ columns: (ColumnRegular> \| ColumnGrouping)[]; }>` |
| `beforecolumnsset` | Emitted before a column update is applied. Listeners can use this event to perform any necessary actions or modifications before the column update is finalized. | `CustomEvent<{ columns: Record>[]>; columnByProp: Record>[]>; columnGrouping: ColumnGroupingCollection; maxLevel: number; sort: Record>>; }>` |
| `beforeedit` | Before the data is edited. To prevent the default behavior of editing data and use your own implementation, call `e.preventDefault()`. To override the edit result with your own value, set the `e.val` property to your desired value. | `CustomEvent>>>` |
| `beforeeditstart` | Emitted before editing starts. Use e.preventDefault() to prevent the default edit behavior. | `CustomEvent>>>` |
| `beforeexport` | Before export Use e.preventDefault() to prevent export Replace data in Event in case you want to modify it in export | `CustomEvent<{ data: DataType[]; } & ColSource>` |
| `beforefilterapply` | Emitted before applying a filter to the data source. Use e.preventDefault() to prevent cell focus change. Modify if you need to change filters. | `CustomEvent<{ collection: Record; }>` |
| `beforefiltertrimmed` | Emitted before applying a filter to the data source. Use e.preventDefault() to prevent the default behavior of trimming values and applying the filter. Modify the `collection` property if you want to change the filters. Modify the `itemsToFilter` property if you want to filter the indexes for trimming. | `CustomEvent<{ collection: Record; itemsToFilter: Record; }>` |
| `beforefocuslost` | Before the grid focus is lost. To prevent the default behavior of changing the cell focus, you can call `e.preventDefault()`. | `CustomEvent> \| undefined; }>` |
| `beforegridrender` | Emmited before the grid is rendered. | `CustomEvent` |
| `beforerange` | Before autofill is applied. Runs before beforeautofill event. Use e.preventDefault() to prevent range. | `CustomEvent<{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }>` |
| `beforerangeedit` | Before applying range data, specifically when a range selection occurs. To customize the data and prevent the default edit data from being set, you can call `e.preventDefault()`. | `CustomEvent` |
| `beforerowdefinition` | Emitted before the row definition is applied. Useful for modifying or preventing the default row definition behavior. | `CustomEvent<{ vals: any; oldVals: any; }>` |
| `beforesorting` | By `SortingPlugin` Triggered immediately after header click. First in sorting event sequence. Ff this event stops no other event called. Use `e.preventDefault()` to prevent sorting. | `CustomEvent<{ column: ColumnRegular>; order: "asc" \| "desc"; additive: boolean; }>` |
| `beforesortingapply` | By `SortingPlugin` After `beforesorting` Triggered after column data updated with new sorting order. Use `e.preventDefault()` to prevent sorting data change. | `CustomEvent<{ column: ColumnRegular>; order: "asc" \| "desc"; additive: boolean; }>` |
| `beforesourceset` | Before main source/rows data apply. You can override data source here | `CustomEvent<{ type: DimensionRows; source: DataType[]; }>` |
| `beforesourcesortingapply` | By `SortingPlugin` Same as `beforesorting` but triggered after `beforeanysource` (when source is changed). Use `e.preventDefault()` to prevent sorting data change. | `CustomEvent<{ type: DimensionRows; sorting?: SortingOrder \| undefined; }>` |
| `beforetrimmed` | Emitted before trimming values. Use e.preventDefault() to prevent the default behavior of trimming values. Modify the `trimmed` property if you want to filter the indexes for trimming. | `CustomEvent<{ trimmed: Record; trimmedType: string; type: string; }>` |
| `contentsizechanged` | New content size has been applied. The size excludes the header. Currently, the event responsible for applying the new content size does not provide the actual size. To retrieve the actual content size, you can utilize the `getContentSize` function after the event has been triggered. | `CustomEvent<"colPinEnd" \| "colPinStart" \| "rgCol" \| "rgRow" \| "rowPinEnd" \| "rowPinStart">` |
| `created` | Emmited after grid created | `CustomEvent` |
| `filterconfigchanged` | Emitted when the filter configuration is changed | `CustomEvent` |
| `headerclick` | On header click. | `CustomEvent>>` |
| `rowdragstart` | This event is triggered when the row order change is started. To prevent the default behavior of changing the row order, you can call `e.preventDefault()`. To change the item name at the start of the row order change, you can set `e.text` to the desired new name. | `CustomEvent` |
| `rowheaderschanged` | Emmited when the row headers are changed. | `CustomEvent` |
| `roworderchanged` | Before the order of `rgRow` is applied. To prevent the default behavior of changing the order of `rgRow`, you can call `e.preventDefault()`. | `CustomEvent<{ from: number; to: number; }>` |
| `sortingconfigchanged` | Emitted when the sorting configuration is changed SortingPlugin subsribed to this event | `CustomEvent<{ columns?: { prop: ColumnProp; order: Order; cellCompare?: CellCompareFunc \| undefined; }[] \| undefined; additive?: boolean \| undefined; }>` |
| `viewportscroll` | Emitted when the viewport is scrolled. Useful for tracking viewport scrolling events. | `CustomEvent` |
## Methods
### `addTrimmed(trimmed: Record, trimmedType?: string, type?: DimensionRows) => Promise; trimmedType: string; type: string; }>>`
Add trimmed by type
#### Parameters
| Name | Type | Description |
| ------------- | ---------------------------- | ----------- |
| `trimmed` | `{ [x: number]: boolean; }` | |
| `trimmedType` | `string` | |
| `type` | `DimensionRowPin \| "rgRow"` | |
#### Returns
Type: `Promise; trimmedType: string; type: string; }>>`
### `clearFocus() => Promise`
Clear current grid focus. Grid has no longer focus on it.
#### Returns
Type: `Promise`
### `clearSorting() => Promise`
Clears column sorting
#### Returns
Type: `Promise`
### `getColumnStore(type?: DimensionCols) => Promise>>`
Provides access to column internal store observer
Can be used for plugin support
#### Parameters
| Name | Type | Description |
| ------ | ---------------------------- | ---------------- |
| `type` | `DimensionColPin \| "rgCol"` | - type of column |
#### Returns
Type: `Promise>, DimensionCols>>>`
### `getColumns() => Promise`
Receive all columns in data source
#### Returns
Type: `Promise>[]>`
### `getContentSize() => Promise`
Get size of content
Including all pinned data
#### Returns
Type: `Promise`
### `getFocused() => Promise`
Get the currently focused cell.
#### Returns
Type: `Promise`
### `getPlugins() => Promise`
Get all active plugins instances
#### Returns
Type: `Promise`
### `getProviders() => Promise`
Get all providers for grid
Useful for external grid integration
#### Returns
Type: `Promise`
### `getSelectedRange() => Promise<(RangeArea & AllDimensionType) | null>`
Get the currently selected Range.
#### Returns
Type: `Promise<(RangeArea & AllDimensionType) | null>`
### `getSource(type?: DimensionRows) => Promise`
Get data from source
#### Parameters
| Name | Type | Description |
| ------ | ---------------------------- | ----------- |
| `type` | `DimensionRowPin \| "rgRow"` | |
#### Returns
Type: `Promise`
### `getSourceStore(type?: DimensionRows) => Promise>>`
Provides access to rows internal store observer
Can be used for plugin support
#### Parameters
| Name | Type | Description |
| ------ | ---------------------------- | ---------------- |
| `type` | `DimensionRowPin \| "rgRow"` | - type of source |
#### Returns
Type: `Promise>>`
### `getVisibleSource(type?: DimensionRows) => Promise`
Get data from visible part of source
Trimmed/filtered rows will be excluded
#### Parameters
| Name | Type | Description |
| ------ | ---------------------------- | ---------------- |
| `type` | `DimensionRowPin \| "rgRow"` | - type of source |
#### Returns
Type: `Promise`
### `refresh(type?: DimensionRows | "all") => Promise`
Refreshes data viewport.
Can be specific part as rgRow or pinned rgRow or 'all' by default.
#### Parameters
| Name | Type | Description |
| ------ | ------------------------ | ----------- |
| `type` | `DimensionRows \| "all"` | |
#### Returns
Type: `Promise`
### `refreshExtraElements() => Promise`
Refresh extra elements. Triggers re-rendering of extra elements and functions.
Part of extraElements and registerVNode methods.
Useful for plugins.
#### Returns
Type: `Promise`
### `scrollToColumnIndex(coordinate?: number) => Promise`
Scrolls viewport to specified column by index.
#### Parameters
| Name | Type | Description |
| ------------ | -------- | ----------- |
| `coordinate` | `number` | |
#### Returns
Type: `Promise`
### `scrollToColumnProp(prop: ColumnProp, dimension?: DimensionTypeCol) => Promise`
Scrolls viewport to specified column by prop
#### Parameters
| Name | Type | Description |
| ----------- | ------------------ | ----------- |
| `prop` | `string \| number` | |
| `dimension` | `"rgCol"` | |
#### Returns
Type: `Promise`
### `scrollToCoordinate(cell: Partial) => Promise`
Scrolls view port to coordinate
#### Parameters
| Name | Type | Description |
| ------ | ------------------------------------------------------- | ----------- |
| `cell` | `{ x?: number \| undefined; y?: number \| undefined; }` | |
#### Returns
Type: `Promise`
### `scrollToRow(coordinate?: number) => Promise`
Scrolls viewport to specified row by index.
#### Parameters
| Name | Type | Description |
| ------------ | -------- | ----------- |
| `coordinate` | `number` | |
#### Returns
Type: `Promise`
### `setCellEdit(rgRow: number, prop: ColumnProp, rowSource?: DimensionRows) => Promise`
Open editor for cell.
#### Parameters
| Name | Type | Description |
| ----------- | ---------------------------- | ----------- |
| `rgRow` | `number` | |
| `prop` | `string \| number` | |
| `rowSource` | `DimensionRowPin \| "rgRow"` | |
#### Returns
Type: `Promise`
### `setCellsFocus(cellStart?: Cell, cellEnd?: Cell, colType?: string, rowType?: string) => Promise`
Set focus range.
#### Parameters
| Name | Type | Description |
| ----------- | -------- | ----------- |
| `cellStart` | `Cell` | |
| `cellEnd` | `Cell` | |
| `colType` | `string` | |
| `rowType` | `string` | |
#### Returns
Type: `Promise`
### `setDataAt({ row, col, colType, rowType, val, skipDataUpdate }: { row: number; col: number; val?: any; skipDataUpdate?: boolean; } & AllDimensionType) => Promise`
Refreshes data at specified cell.
Useful for performance optimization.
No viewport update will be triggered.
#### Parameters
| Name | Type | Description |
| ----- | ---------------------------------------------------------------------------------------------------- | ----------- |
| `__0` | `{ row: number; col: number; val?: any; skipDataUpdate?: boolean \| undefined; } & AllDimensionType` | |
#### Returns
Type: `Promise`
### `updateColumnSorting(column: Pick, order: "asc" | "desc" | undefined, additive: boolean) => Promise`
Update column sorting
#### Parameters
| Name | Type | Description |
| ---------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `column` | `{ prop: ColumnProp; cellCompare?: CellCompareFunc> \| undefined; }` | - column prop and cellCompare |
| `order` | `"asc" \| "desc" \| undefined` | - order to apply |
| `additive` | `boolean` | - if false will replace current order later passed to SortingPlugin |
#### Returns
Type: `Promise`
### `updateColumns(cols: ColumnRegular[]) => Promise`
Update columns
#### Parameters
| Name | Type | Description |
| ------ | -------------------------------------------------------- | ----------- |
| `cols` | `ColumnRegular>[]` | |
#### Returns
Type: `Promise`
## Slots
| Slot | Description |
| ----------------------------------- | -------------- |
| `"data-{column-type}-{row-type}."` | |
| `"focus-{column-type}-{row-type}."` | |
| `"footer"` | Footer slot. |
| `"header"` | Header slot. |
| `"viewport"` | Viewport slot. |
## Dependencies
### Depends on
- [revogr-row-headers](https://rv-grid.com/guide/rowHeaders)
- [revogr-header](https://rv-grid.com/guide/header)
- [revogr-overlay-selection](https://rv-grid.com/guide/overlay)
- [revogr-data](https://rv-grid.com/guide/data)
- [revogr-temp-range](https://rv-grid.com/guide/selectionTempRange)
- [revogr-focus](https://rv-grid.com/guide/selectionFocus)
- [revogr-viewport-scroll](https://rv-grid.com/guide/scroll)
- [revogr-scroll-virtual](https://rv-grid.com/guide/scrollable)
- revogr-attribution
- revogr-extra
### Graph
```mermaid
graph TD;
revo-grid --> revogr-row-headers
revo-grid --> revogr-header
revo-grid --> revogr-overlay-selection
revo-grid --> revogr-data
revo-grid --> revogr-temp-range
revo-grid --> revogr-focus
revo-grid --> revogr-viewport-scroll
revo-grid --> revogr-scroll-virtual
revo-grid --> revogr-attribution
revo-grid --> revogr-extra
revogr-row-headers --> revogr-data
revogr-row-headers --> revogr-viewport-scroll
revogr-row-headers --> revogr-header
revogr-data --> vnode-html
revogr-overlay-selection --> revogr-edit
revogr-overlay-selection --> revogr-clipboard
revogr-overlay-selection --> revogr-order-editor
revogr-extra --> revogr-extra
style revo-grid fill:#f9f,stroke:#333,stroke-width:4px
```
----------------------------------------------
*Built with ❤️ by Revolist OU*
---
# Revogrid Events
Source: https://rv-grid.com/guide/api/events
# Revogrid Events
| Name | Type | Component | Description |
| ---- | ---- | --------- | ----------- |
| contentsizechanged | `"colPinEnd" \| "colPinStart" \| "rgCol" \| "rgRow" \| "rowPinEnd" \| "rowPinStart"` | revo-grid | New content size has been applied. The size excludes the header. Currently, the event responsible for applying the new content size does not provide the actual size. To retrieve the actual content size, you can utilize the `getContentSize` function after the event has been triggered. |
| beforeedit | `BeforeSaveDataDetails>>` | revo-grid | Before the data is edited. To prevent the default behavior of editing data and use your own implementation, call `e.preventDefault()`. To override the edit result with your own value, set the `e.val` property to your desired value. |
| beforerangeedit | `TModel` | revo-grid | Before applying range data, specifically when a range selection occurs. To customize the data and prevent the default edit data from being set, you can call `e.preventDefault()`. |
| afteredit | `BeforeSaveDataDetails>> \| D \| K` | revo-grid | After data applied or range changed. |
| beforeautofill | `{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }` | revo-grid | Before autofill is applied. To prevent the default behavior of applying the edit data, you can call `e.preventDefault()`. |
| beforerange | `{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }` | revo-grid | Before autofill is applied. Runs before beforeautofill event. Use e.preventDefault() to prevent range. |
| afterfocus | `FocusAfterRenderEvent>` | revo-grid | After focus render finished. Can be used to access a focus element through `event.target`. This is just a duplicate of `afterfocus` from `revogr-focus.tsx`. |
| roworderchanged | `{ from: number; to: number; }` | revo-grid | Before the order of `rgRow` is applied. To prevent the default behavior of changing the order of `rgRow`, you can call `e.preventDefault()`. |
| beforesorting | `{ column: ColumnRegular>; order: "asc" \| "desc"; additive: boolean; }` | revo-grid | By `SortingPlugin` Triggered immediately after header click. First in sorting event sequence. Ff this event stops no other event called. Use `e.preventDefault()` to prevent sorting. |
| beforesourcesortingapply | `{ type: DimensionRows; sorting?: SortingOrder \| undefined; }` | revo-grid | By `SortingPlugin` Same as `beforesorting` but triggered after `beforeanysource` (when source is changed). Use `e.preventDefault()` to prevent sorting data change. |
| beforesortingapply | `{ column: ColumnRegular>; order: "asc" \| "desc"; additive: boolean; }` | revo-grid | By `SortingPlugin` After `beforesorting` Triggered after column data updated with new sorting order. Use `e.preventDefault()` to prevent sorting data change. |
| aftersortingapply | `{ sorting?: SortingOrder \| undefined; sortingColumns?: SortingColumnMap \| undefined; sortingOrder?: SortingColumnOrder \| undefined; types: DimensionRows[]; }` | revo-grid | By `SortingPlugin` Triggered after sorting has been applied and completed. Provides final sorting state and sorting column metadata when available. |
| rowdragstart | `TModel` | revo-grid | This event is triggered when the row order change is started. To prevent the default behavior of changing the row order, you can call `e.preventDefault()`. To change the item name at the start of the row order change, you can set `e.text` to the desired new name. |
| headerclick | `ColumnRegular>` | revo-grid | On header click. |
| beforecellfocus | `BeforeSaveDataDetails>>` | revo-grid | Before the cell focus is changed. To prevent the default behavior of changing the cell focus, you can call `e.preventDefault()`. |
| beforefocuslost | `null \| { model: any; cell: Cell; colType: DimensionCols; rowType: DimensionRows; column?: ColumnRegular> \| undefined; }` | revo-grid | Before the grid focus is lost. To prevent the default behavior of changing the cell focus, you can call `e.preventDefault()`. |
| beforesourceset | `{ type: DimensionRows; source: DataType[]; }` | revo-grid | Before main source/rows data apply. You can override data source here |
| beforeanysource | `{ type: DimensionRows; source: DataType[]; }` | revo-grid | Before data apply on any source type. Can be source from pinned and main viewport. You can override data source here |
| aftersourceset | `{ type: DimensionRows; source: DataType[]; }` | revo-grid | After main source/rows updated |
| afteranysource | `{ type: DimensionRows; source: DataType[]; }` | revo-grid | Emitted after each source update, whether from the pinned or main viewport. Useful for tracking all changes originating from sources in both the pinned and main viewports. |
| beforecolumnsgather | `{ columns: (ColumnRegular> \| ColumnGrouping)[]; }` | revo-grid | Emitted before user column definitions are gathered into the internal column collection. Listeners can replace `detail.columns` to rewrite the raw column set before RevoGrid normalizes it. |
| beforecolumnsset | `{ columns: Record>[]>; columnByProp: Record>[]>; columnGrouping: ColumnGroupingCollection; maxLevel: number; sort: Record>>; }` | revo-grid | Emitted before a column update is applied. Listeners can use this event to perform any necessary actions or modifications before the column update is finalized. |
| beforecolumnapplied | `{ columns: Record>[]>; columnByProp: Record>[]>; columnGrouping: ColumnGroupingCollection; maxLevel: number; sort: Record>>; }` | revo-grid | Emitted before a column update is applied, after the column set is gathered and the viewport is updated. Useful for performing actions or modifications before the final application of the column update. |
| aftercolumnsset | `{ columns: ColumnCollection; order: SortingOrder; }` | revo-grid | Column updated |
| beforefilterapply | `{ collection: Record; }` | revo-grid | Emitted before applying a filter to the data source. Use e.preventDefault() to prevent cell focus change. Modify if you need to change filters. |
| beforefiltertrimmed | `{ collection: Record; itemsToFilter: Record; }` | revo-grid | Emitted before applying a filter to the data source. Use e.preventDefault() to prevent the default behavior of trimming values and applying the filter. Modify the `collection` property if you want to change the filters. Modify the `itemsToFilter` property if you want to filter the indexes for trimming. |
| beforetrimmed | `{ trimmed: Record; trimmedType: string; type: string; }` | revo-grid | Emitted before trimming values. Use e.preventDefault() to prevent the default behavior of trimming values. Modify the `trimmed` property if you want to filter the indexes for trimming. |
| aftertrimmed | `any` | revo-grid | Emitted after trimmed values have been applied. Useful for notifying when trimming of values has taken place. |
| viewportscroll | `D` | revo-grid | Emitted when the viewport is scrolled. Useful for tracking viewport scrolling events. |
| beforeexport | `{ data: DataType[]; } & ColSource` | revo-grid | Before export Use e.preventDefault() to prevent export Replace data in Event in case you want to modify it in export |
| beforeeditstart | `BeforeSaveDataDetails>>` | revo-grid | Emitted before editing starts. Use e.preventDefault() to prevent the default edit behavior. |
| aftercolumnresize | `{ [index: number]: ColumnRegular>; }` | revo-grid | Emitted after column resizing. Useful for retrieving the resized columns. |
| beforerowdefinition | `{ vals: any; oldVals: any; }` | revo-grid | Emitted before the row definition is applied. Useful for modifying or preventing the default row definition behavior. |
| filterconfigchanged | `any` | revo-grid | Emitted when the filter configuration is changed |
| sortingconfigchanged | `{ columns?: { prop: ColumnProp; order: Order; cellCompare?: CellCompareFunc \| undefined; }[] \| undefined; additive?: boolean \| undefined; }` | revo-grid | Emitted when the sorting configuration is changed SortingPlugin subsribed to this event |
| rowheaderschanged | `any` | revo-grid | Emmited when the row headers are changed. |
| beforegridrender | `any` | revo-grid | Emmited before the grid is rendered. |
| aftergridrender | `any` | revo-grid | Emmited after the grid is rendered. |
| aftergridinit | `any` | revo-grid | Emmited after the grid is initialized. Connected to the DOM. |
| additionaldatachanged | `any` | revo-grid | Emmited after the additional data is changed |
| afterthemechanged | `string` | revo-grid | Emmited after the theme is changed |
| created | `any` | revo-grid | Emmited after grid created |
| beforepaste | `{ raw: string; isHTML: boolean; event: ClipboardEvent; dataText: string; }` | revogr-clipboard | Paste 1. Fired before paste applied to the grid defaultPrevented - if true, paste will be canceled |
| beforepasteapply | `{ raw: string; parsed: string[][]; dataText: string; event: ClipboardEvent; }` | revogr-clipboard | Paste 2. Fired before paste applied to the grid and after data parsed |
| pasteregion | `string[][]` | revogr-clipboard | Paste 3. Internal method. When data region is ready pass it to the top. |
| afterpasteapply | `{ raw: string; parsed: string[][]; dataText: string; event: ClipboardEvent; }` | revogr-clipboard | Paste 4. Fired after paste applied to the grid defaultPrevented - if true, paste will be canceled |
| beforecut | `{ event: ClipboardEvent; }` | revogr-clipboard | Cut 1. Fired before cut triggered defaultPrevented - if true, cut will be canceled |
| clearregion | `DataTransfer` | revogr-clipboard | Cut 2. Clears region when cut is done |
| beforecopy | `{ event: ClipboardEvent; }` | revogr-clipboard | Copy 1. Fired before copy triggered defaultPrevented - if true, copy will be canceled |
| beforecopyapply | `{ event: DataTransfer; data?: string[][] \| undefined; }` | revogr-clipboard | Copy Method 1. Fired before copy applied to the clipboard from outside. defaultPrevented - if true, copy will be canceled |
| copyregion | `DataTransfer` | revogr-clipboard | Copy 2. Fired when region copied defaultPrevented - if true, copy will be canceled |
| beforerowrender | `BeforeRowRenderEvent` | revogr-data | Before each row render |
| afterrender | `{ type: DimensionRows; }` | revogr-data | When data render finished for the designated type |
| beforecellrender | `BeforeCellRenderEvent, ColumnRegular>, ColumnProp>>` | revogr-data | Before each cell render function. Allows to override cell properties |
| beforedatarender | `AllDimensionType` | revogr-data | Before data render |
| dragstartcell | `DragStartEvent, ColumnRegular>>` | revogr-data | Event emitted on cell drag start |
| celleditinit | `{ rgRow: number; rgCol: number; type: DimensionRows; prop: ColumnProp; val: any; preventFocus?: boolean \| undefined; }` | revogr-edit | Cell edit event initiator, first in the cellEdit event chain |
| closeedit | `boolean \| undefined` | revogr-edit | Close editor event pass true if requires focus next |
| filterChange | `MultiFilterItem` | revogr-filter-panel | |
| resetChange | `number \| string` | revogr-filter-panel | |
| beforefocusrender | `FocusRenderEvent` | revogr-focus | Before focus render event. Can be prevented by event.preventDefault(). If preventDefault used slot will be rendered. |
| beforescrollintoview | `{ el: HTMLElement; }` | revogr-focus | Before focus changed verify if it's in view and scroll viewport into this view Can be prevented by event.preventDefault() |
| afterfocus | `FocusAfterRenderEvent>` | revogr-focus | Used to setup properties after focus was rendered |
| beforeheaderclick | `{ index: number; originalEvent: MouseEvent; column: ColumnRegular>; providers: ProvidersColumns; }` | revogr-header | On initial header click |
| headerresize | `{ [x: string]: number; }` | revogr-header | On header resize |
| beforeheaderresize | `ColumnRegular>[]` | revogr-header | On before header resize |
| headerdblclick | `{ index: number; originalEvent: MouseEvent; column: ColumnRegular>; providers: ProvidersColumns; }` | revogr-header | On header double click |
| beforeheaderrender | `{ column: VirtualPositionItem; additionalData: any; data: ColumnTemplateProp; range?: RangeArea \| null \| undefined; canResize?: boolean \| undefined; canFilter?: boolean \| undefined; renderOffset?: number \| undefined; onResize?(e: ResizeEvent): void; onClick?(data: InitialHeaderClick): void; onDblClick?(data: InitialHeaderClick): void; } & Partial>` | revogr-header | Before each header cell render function. Allows to override cell properties |
| beforegroupheaderrender | `{ level: number; start: number; end: number; group: Group; providers: ProvidersColumns; additionalData: any; canResize?: boolean \| undefined; renderOffset?: number \| undefined; onResize?(e: ResizeEvent): void; } & Partial>` | revogr-header | Before each group header cell render function. Allows to override group header cell properties |
| afterheaderrender | `ProvidersColumns` | revogr-header | After all header cells rendered. Finalizes cell rendering. |
| columndragstart | `ColumnDragStartEventData` | revo-grid | Triggered when a column drag operation starts. Call preventDefault() to prevent the column move. |
| columndragmousemove | `MouseEvent` | revo-grid | Fired while a column drag operation is moving. |
| beforecolumndragend | `BeforeColumnDragEndEventData` | revo-grid | Fired before the column drag operation is applied. Call preventDefault() to reject the move. |
| columndragend | `ColumnDragEventData` | revo-grid | Fired when the column drag operation completes. Includes reordered columns, physical order, and viewport type. |
| beforerowresize | `RowResizeEventDetail` | revo-grid | Fired before a row-header resize gesture starts. Call preventDefault() to reject the gesture. |
| rowresize | `RowResizeEventDetail` | revo-grid | Fired after each live row-height update. |
| afterrowresize | `RowResizeEventDetail` | revo-grid | Fired after a row resize gesture commits. |
| rowresizecancel | `RowResizeCancelEventDetail` | revo-grid | Fired after an interrupted row resize restores the original heights. |
| rowdragstartinit | `TModel` | revogr-order-editor | Row drag started |
| rowdragendinit | `{ rowType: DimensionRows; }` | revogr-order-editor | Row drag ended started |
| rowdragmoveinit | `PositionItem & { rowType: DimensionRows; }` | revogr-order-editor | Row move started |
| rowdragmousemove | `Cell & { rowType: DimensionRows; }` | revogr-order-editor | Row mouse move started |
| rowdropinit | `{ from: number; to: number; rowType: DimensionRows; }` | revogr-order-editor | Row dragged, new range ready to be applied |
| roworderchange | `{ from: number; to: number; rowType: DimensionRows; }` | revogr-order-editor | Row drag ended finished. Time to apply data |
| beforecopyregion | `any` | revogr-overlay-selection | Before clipboard copy happened. Validate data before copy. To prevent the default behavior of editing data and use your own implementation, call `e.preventDefault()`. |
| beforepasteregion | `any` | revogr-overlay-selection | Before region paste happened. |
| celleditapply | `BeforeSaveDataDetails>>` | revogr-overlay-selection | Cell edit apply to the data source. Triggers datasource edit on the root level. |
| beforecellfocusinit | `BeforeSaveDataDetails>>` | revogr-overlay-selection | Before cell focus. |
| beforenextvpfocus | `Cell` | revogr-overlay-selection | Fired when change of viewport happens. Usually when we switch between pinned regions. |
| setedit | `BeforeSaveDataDetails>>` | revogr-overlay-selection | Set edit cell. |
| beforeapplyrange | `FocusRenderEvent` | revogr-overlay-selection | Before range applied. First step in triggerRangeEvent. |
| beforesetrange | `any` | revogr-overlay-selection | Before range selection applied. Second step in triggerRangeEvent. |
| setrange | `RangeArea & { type: MultiDimensionType; }` | revogr-overlay-selection | Set range. Third step in triggerRangeEvent. |
| beforeeditrender | `FocusRenderEvent` | revogr-overlay-selection | Before editor render. |
| selectall | `any` | revogr-overlay-selection | Select all cells from keyboard. |
| canceledit | `any` | revogr-overlay-selection | Cancel edit. Used for editors support when editor close requested. |
| settemprange | `null \| { type: string; area: RangeArea; }` | revogr-overlay-selection | Set temp range area during autofill. |
| beforesettemprange | `{ tempRange: Nullable \| null; } & EventData & AllDimensionType` | revogr-overlay-selection | Before set temp range area during autofill. |
| applyfocus | `FocusRenderEvent` | revogr-overlay-selection | Before cell get focused. To prevent the default behavior of applying the edit data, you can call `e.preventDefault()`. |
| focuscell | `ApplyFocusEvent & FocusRenderEvent` | revogr-overlay-selection | Cell get focused. To prevent the default behavior of applying the edit data, you can call `e.preventDefault()`. |
| beforerangedataapply | `FocusRenderEvent` | revogr-overlay-selection | Range data apply. |
| selectionchangeinit | `{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }` | revogr-overlay-selection | Autofill data in range. First step in applyRangeWithData |
| beforerangecopyapply | `{ type: DimensionRows; colType: DimensionCols; newRange: RangeArea; oldRange: RangeArea; mapping: OldNewRangeMapping; newData: { [newRowIndex: number]: DataType; }; }` | revogr-overlay-selection | Before range copy. |
| rangeeditapply | `TModel` | revogr-overlay-selection | Range data apply. Triggers datasource edit on the root level. |
| clipboardrangecopy | `RangeClipboardCopyEventProps` | revogr-overlay-selection | Range copy. |
| clipboardrangepaste | `RangeClipboardPasteEvent>` | revogr-overlay-selection | Range paste event. |
| beforekeydown | `{ original: KeyboardEvent; } & EventData` | revogr-overlay-selection | Before key up event proxy, used to prevent key up trigger. If you have some custom behaviour event, use this event to check if it wasn't processed by internal logic. Call preventDefault(). |
| beforekeyup | `{ original: KeyboardEvent; } & EventData` | revogr-overlay-selection | Before key down event proxy, used to prevent key down trigger. If you have some custom behaviour event, use this event to check if it wasn't processed by internal logic. Call preventDefault(). |
| beforecellsave | `any` | revogr-overlay-selection | Runs before cell save. Can be used to override or cancel original save. |
| celledit | `{ rgRow: number; rgCol: number; type: DimensionRows; prop: ColumnProp; val: any; preventFocus?: boolean \| undefined; }` | revogr-overlay-selection | Runs when edit finished save started, first in chain event |
| scrollview | `D` | revogr-row-headers | Scroll viewport |
| ref | `ElementScroll` | revogr-row-headers | Register element to scroll |
| scrollvirtual | `D` | revogr-scroll-virtual | Scroll event |
| scrollviewport | `D` | revogr-viewport-scroll | Before scroll event |
| resizeviewport | `{ dimension: DimensionType; size: number; rowHeader?: boolean \| undefined; }` | revogr-viewport-scroll | Viewport resize |
| scrollchange | `{ type: DimensionType; hasScroll: boolean; }` | revogr-viewport-scroll | Triggered on scroll change, can be used to get information about scroll visibility |
| scrollviewportsilent | `D` | revogr-viewport-scroll | Silently scroll to coordinate Made to align negative coordinates for mobile devices |
| html | `{ html: string; vnodes: VNode[] \| null; }` | vnode-html | |
*Built with ❤️ by Revolist OU*
---
# RevoGrid Viewports
Source: https://rv-grid.com/guide/viewports
Description: Understand RevoGrid viewport architecture for virtual rows, virtual columns, pinned rows, pinned columns, dimensions, and scrolling behavior.
# Understanding Viewports
RevoGrid has pinned rows (top and bottom) and pinned columns (left and right), which leads to three different viewports for each type:
---
---
For rows, the viewports are:
- `rowPinStart`
- `rgRow`
- `rowPinEnd`
For columns, the viewports are:
- `colPinStart`
- `rgCol`
- `colPinEnd`
This structure was designed for a unified grid architecture, making the code easier to read and understand. However, this introduces some advanced concepts that need to be supported. Specifically, it means that different events will return virtual indexes instead of real ones.
## Understanding Virtual Indexes
In RevoGrid, the concept of virtual indexes is crucial for efficiently managing the layout of the grid, especially when working with pinned rows and columns. These indexes allow the grid to optimize rendering and event handling, ensuring that the user experience remains smooth even with large datasets.
### Row Virtual Indexes
For rows, the virtual indexes are structured as follows:
- The first array represents the pinned rows at the top (`rowPinStart`).
- The second array represents the main body of the grid rows (`rgRow`).
- The third array represents the pinned rows at the bottom (`rowPinEnd`).
For example, the virtual row indexes might look like this:
```
[
[0, 1, 2, ...], // Pinned rows at the top
[0, 1, 2, 3, 4, ...], // Main body of the grid
[0, 1, ...] // Pinned rows at the bottom
]
```
This structure indicates that when you interact with a cell in the grid, the event handling will refer to these virtual indexes instead of the actual indexes in your data source.
For instance, if you are working with the main body of the grid and you access the first row, you will receive `rowIndex` of `0` from the second array, but this corresponds to the actual data index in your dataset.
### Column Virtual Indexes
Similarly, for columns, the virtual indexes are organized to account for pinned columns:
- The first set of indexes represents the pinned columns on the left (`colPinStart`).
- The second set represents the main grid columns (`rgCol`).
- The last set represents the pinned columns on the right (`colPinEnd`).
The structure for columns would look like this:
```
[
[0, 1, ...], // Pinned columns on the left
[0, 1, 2, 3, ...], // Main grid columns
[0, 1, ...] // Pinned columns on the right
]
```
### Implications of Using Virtual Indexes
When working with events, it’s important to remember that every event dispatched from the grid will return these virtual indexes instead of the actual indexes from your dataset. This design choice simplifies event management but also requires developers to consider how they map these indexes back to their underlying data model.
For example, if you have an event such as `beforeedit`, the event details may look like this:
```typescript
export type BeforeSaveDataDetails = {
prop: ColumnProp;
model: DataType;
val?: SaveData;
rowIndex: number; // virtual row index
colIndex: number; // virtual column index
colType: DimensionCols;
type: DimensionRows;
};
```
Here, `rowIndex` and `colIndex` refer to the virtual indexes, which means that if you want to retrieve the actual data from your source, you may need to perform additional calculations or mappings based on the grid’s layout.
## Why Ranges Stay Inside One Viewport
Range coordinates are only complete when they are paired with their viewport
types. A range area stores virtual coordinates:
```ts
type RangeArea = {
x: ColIndex;
y: RowIndex;
x1: ColIndex;
y1: RowIndex;
};
```
The range event adds the row and column viewport types around those coordinates:
```ts
type ChangedRange = {
type: DimensionRows;
colType: DimensionCols;
newRange: RangeArea;
oldRange: RangeArea;
};
```
This is why a single range selection, clipboard fill, or autofill operation
should stay inside one row viewport and one column viewport. `x: 0` in
`colPinStart` and `x: 0` in `rgCol` are different virtual coordinate systems.
The same applies to `rowPinStart`, `rgRow`, and `rowPinEnd`.
Autofill follows the same model. It reads the selected data from
`providers.data.stores[type]` and resolves columns through
`providers.column.stores[colType]`. If an autofill drag crossed from a pinned
viewport into the main viewport, it would no longer be one rectangular
`ChangedRange`; it would be several viewport-scoped ranges stitched together.
For example, imagine a grid with one pinned top row and a vertically scrolled
main viewport:
- `rowPinStart` shows pinned row `0`.
- `rgRow` is scrolled so the first visible main row is much lower in the dataset.
- The user starts autofill from the pinned row and drags into a visible main row.
If RevoGrid treated that as one range, the write target would be unclear. Should
it fill only the cells that are visible on screen? Should it fill every main row
between the pinned row and the scrolled row, including rows hidden behind the
scroll gap? Or should the coordinates stay in the pinned row store, where the
main viewport row does not exist? Each interpretation can surprise users and
plugin authors in a different way.
That stitching is a bad fit for the grid model because it hides where the
operation actually writes, makes virtual indexes ambiguous, and can mix pinned
and main data stores in one gesture. If a workflow needs to update pinned and
main areas together, model it as explicit separate operations per viewport
instead of one cross-viewport autofill.
This is different from a spreadsheet such as Excel. Excel's Freeze Panes keeps
rows or columns visible while another worksheet area scrolls, but the worksheet
still has one continuous row and column address space. RevoGrid's pinned areas
are separate row and column viewport stores, so the same visual gesture cannot
be interpreted as one continuous autofill range without adding rules for the
hidden rows and viewport boundaries.
## Practical Example
Let’s say you have a grid with pinned rows and columns, and a user interacts with a cell in the main grid.
When you handle the `beforeedit` event:
```ts
revogrid.addEventListener('beforeedit', (event: HTMLRevoGridElementEventMap['beforeedit']) => {
const { rowIndex, colIndex } = event.detail;
console.log(rowIndex, colIndex);
})
```
You might receive:
```ts
{
rowIndex: 0, // This refers to the first row in the main grid (rgRow)
colIndex: 1, // This refers to the second column in the main grid (rgCol)
}
```
But physically it could be 2, 3, or 4 row and column indexes. If you want to get the actual data from your dataset, you would need to translate these virtual indexes back to your data model, taking into account any pinned rows or columns.
In this type definition, `BeforeSaveDataDetails` includes information about the dimension type for both rows and columns, with indexes provided in a virtual coordinate system per viewport. While you typically won’t encounter this in standard usage, it's crucial to understand if you’re developing advanced plugins.
```ts
interface HTMLRevoGridElementEventMap {
//...
"beforeedit": BeforeSaveDataDetails;
//...
}
type BeforeSaveDataDetails = {
prop: ColumnProp;
model: DataType;
val?: SaveData;
rowIndex: number; // virtual row index
colIndex: number; // virtual column index
colType: DimensionCols;
type: DimensionRows;
};
```
### Dimension Types
To clarify the dimension types used in RevoGrid, consider the following type definitions:
```typescript
export type DimensionTypeRow = 'rgRow';
export type DimensionTypeCol = 'rgCol';
export type DimensionColPin = 'colPinStart' | 'colPinEnd';
export type DimensionRowPin = 'rowPinStart' | 'rowPinEnd';
export type DimensionType = DimensionTypeCol | DimensionTypeRow;
export type DimensionCols = DimensionColPin | DimensionTypeCol;
export type DimensionRows = DimensionTypeRow | DimensionRowPin;
export type MultiDimensionType = DimensionCols | DimensionRows;
```
These types help in managing the various dimensions and their respective states within the grid, ensuring that your code can effectively handle both pinned and unpinned rows and columns.
Understanding the viewport system in RevoGrid Pro is vital for developers looking to implement advanced features and plugins. By familiarizing yourself with the virtual indexes and the corresponding dimension types, you can ensure that your implementation remains robust and effective.
As you develop your applications, keep these concepts in mind to harness the full potential of RevoGrid's capabilities.
Read more about render in proxy items [here](https://rv-grid.com/guide/proxy-items)
## Index Types Explained
1. **Physical Indexes**: The actual position of items in the source data array
2. **Virtual Indexes**: The visible position of items in the viewport/UI
### Physical Indexes
- These are the actual positions in the source data array (`source[]`)
- They remain constant as long as the data source isn't modified
- Used for direct data access and modifications
- Stored in the `source` array of the data store
### Virtual Indexes
- These represent the visible positions in the UI
- Managed through the `items[]` array which maps virtual indexes to physical ones
- Change dynamically based on scrolling, filtering, and grouping
- Used for viewport rendering and user interactions
## Key Conversion Functions
### Physical to Virtual Index Conversion
```typescript
// Returns the virtual index for a given physical index
function getSourceItemVirtualIndexByProp(store, prop) {
const items = store.get('items');
const source = store.get('source');
const physicalIndex = findIndex(source, { prop });
return items.indexOf(physicalIndex);
}
```
### Virtual to Physical Index Conversion
```typescript
// Returns the physical index for a given virtual index
function getPhysical(store, virtualIndex) {
const items = store.get('items');
return items[virtualIndex];
}
```
## Data Access Methods
### Getting Source Items
1. **By Virtual Index**:
```typescript
function getSourceItem(store, virtualIndex) {
const source = store.get('source');
return source[getPhysical(store, virtualIndex)];
}
```
2. **All Visible Items**:
```typescript
function getVisibleSourceItem(store) {
const source = store.get('source');
return store.get('items').map(v => source[v]);
}
```
## Data Modification
### Updating Source Data
1. **By Virtual Index**:
```typescript
function setSourceByVirtualIndex(store, modelByIndex, mutate = true)
```
- Updates data using virtual indexes as reference
- `modelByIndex`: Object with virtual indexes as keys and new values
- `mutate`: If true, triggers a re-render
2. **By Physical Index**:
```typescript
function setSourceByPhysicalIndex(store, modelByIndex, mutate = true)
```
- Updates data using physical indexes directly
- `modelByIndex`: Object with physical indexes as keys and new values
- `mutate`: If true, triggers a re-render
## Use Cases
1. **Scrolling**: Virtual indexes change while physical indexes remain constant
2. **Data Updates**: Physical indexes are used for data modifications
3. **Rendering**: Virtual indexes determine what's visible in the viewport
4. **Sorting/Filtering**: Modifies the mapping between virtual and physical indexes
## Best Practices
1. Use virtual indexes when dealing with UI interactions
2. Use physical indexes when modifying the underlying data
3. Always use the appropriate conversion functions when switching between index types
4. Be aware that virtual indexes can change during operations like sorting or filtering
## Related guides
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
Read more about render behavior in [proxy items](https://rv-grid.com/guide/proxy-items).
---
# Data Grid Column Configuration
Source: https://rv-grid.com/guide/column
Description: Configure RevoGrid columns with properties for sizing, grouping, pinning, templates, readonly behavior, column types, and header options.
# Column Configuration in Data Grid
[Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular)
A vertical line in the grid that categorizes the data to be displayed. Columns in RevoGrid can be configured with features like sorting, filtering, and custom cell rendering.
```typescript
const columns: ColumnRegular[] = [
{ prop: 'id', name: 'ID' },
{ prop: 'name', name: 'Name' },
{ prop: 'age', name: 'Age' },
{ prop: 'email', name: 'Email' },
];
```
:::tip
Check [Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular) for more information.
:::
To set the size of a column in RevoGrid, you can use the `size`, `minSize`, and `maxSize` properties within your column definition. These properties allow you to control the width of each column, ensuring that your grid is displayed exactly as you need it.
Here’s how you can set the size for a column:
## Column Size
You can specify a fixed size for a column using the `size` property. This value is the width of the column in pixels.
```typescript
const columns = [
{ prop: 'id', name: 'ID', size: 100 }, // Column width is set to 100px
{ prop: 'name', name: 'Name', size: 150 }, // Column width is set to 150px
{ prop: 'age', name: 'Age', size: 80 }, // Column width is set to 80px
];
```
### Example: Column Sizes
Here’s a full example of how you might set up your columns in a RevoGrid with specific sizes:
```typescript
import { defineCustomElements } from '@revolist/revogrid/loader'
defineCustomElements()
const grid = document.querySelector('revo-grid')
if (grid) {
grid.columns = [
{ prop: 'id', name: 'ID', size: 100 },
{ prop: 'name', name: 'Name', size: 150 },
{ prop: 'age', name: 'Age', size: 80 },
]
grid.source = [
{ id: 1, name: 'Alice', age: 30 },
{ id: 2, name: 'Bob', age: 25 },
{ id: 3, name: 'Charlie', age: 35 },
]
}
```
In this example:
- The `ID` column has a fixed width of 100px.
- The `Name` column has a base width of 150px.
- The `Age` column has a base width of 80px.
## Advanced Column Features
RevoGrid offers advanced cell features, including:
- [Column Selection](https://rv-grid.com/guide/column/selection.pro)
- [Column Spanning](https://rv-grid.com/guide/column/span.pro)
- [Advanced Column Stretching](https://rv-grid.com/guide/column/stretch.pro)
- [Other Features](https://rv-grid.com/pro)
---
# Autosize feature
Source: https://rv-grid.com/guide/column/autosize
# Autosize feature
Autosize is aiming to provide intuitive functionality of content dependent entities. Meanwhile some limitations applied.
## Column autosize
In order to achieve column autosize support you have to set `autoSizeColumn` grid property.
`autoSizeColumn` accept different options. The easiest way to start with to use excel like option: `autoSizeColumn = true` (by default it's `false`).
Based on this option every column which has `autoSize: true` property can be recalculated on column header separator double click.
### Quick start
```js
// define autosize per column, if you don't use advance config option allColumns (read below section #Advance usage)
const columns = [{ prop: 'myField', autoSize: true }];
const rows = [{ 'myField': 'my long-long field' }];
const grid = document.querySelector('revo-grid');
grid.autoSizeColumn = true;
grid.source = rows;
grid.columns = columns;
```
### Advance usage
`autoSizeColumn` can be set up as a config object with optional parameters.
```js
grid.autoSizeColumn = {
mode: 'autoSizeOnTextOverlap'
};
```
``` ts
type AutoSizeColumnConfig = {
// ui behavior mode
mode?: ColumnAutoSizeMode;
/**
* autoSize for all columns
* if allColumnes true all columns treated as autoSize, worse for performance
* false by default
*/
allColumns?: boolean;
/**
* assumption per characted size
* improves performance
* by default defined as 7px per char, can be changed in this config
*/
letterBlockSize?: number;
/** make size calculation exact
* by default it based on assumption each character takes some space defined in letterBlockSize */
preciseSize?: boolean;
};
```
### Brief modes description
Column autosize comes in different variation based on user necessity. Each mode has it's own benefits and downsides:
```ts
enum ColumnAutoSizeMode {
// increases column width on header click according the largest text value
headerClickAutosize = 'headerClickAutoSize',
// increases column width on data set and text edit, decreases performance
autoSizeOnTextOverlap = 'autoSizeOnTextOverlap',
// increases and decreases column width based on all items sizes, worst for performance
autoSizeAll = 'autoSizeAll'
}
```
Visit our [demo](https://rv-grid.com/demo/) for real live sample.
::: warning
Currently AutoSize works in Beta mode. Only text autosize supported. Mapped values and custom renders can't be autosized at this moment and require different plugin approach based on per column prerender.
:::
::: tip
It's recommended to check autoSizeColumn.ts plugin for better understanding of all options.
:::
---
# Column Header Template
Source: https://rv-grid.com/guide/column/header.template
# Column Header Template
[Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular) [Type: ColumnTemplateFunc](https://rv-grid.com/guide/types/TypeAlias.ColumnTemplateFunc)
This article explaines how to use custom header function to display HTML content in a header.
This is a powerful feature.
`Remember` to escape any HTML code that could be used for XSS attacks.
:::tip
Check [Type: ColumnTemplateFunc](https://rv-grid.com/guide/types/TypeAlias.ColumnTemplateFunc) for more information.
:::
```ts
const columns: ColumnRegular[] = [
{
name: 'Person name',
prop: 'name',
// use this to return custom html per column
columnTemplate: (
createElement: HyperFunc,
props: ColumnTemplateProp,
additionalData?: any
) => {
return createElement(
'span',
{
style: {
color: 'red',
},
},
column.name
)
},
},
]
```
## Using Keys in Header Templates
> [!IMPORTANT]
> **Keys are essential for VNode reconciliation.** When rendering lists or dynamic content, always provide unique keys to help the virtual DOM accurately identify, track, and update nodes. Use keys thoughtfully, as incorrect usage can lead to inefficient updates or unexpected behavior.
When rendering multiple child elements in a header template, provide unique keys:
```ts
const columns: ColumnRegular[] = [
{
name: 'Actions',
prop: 'actions',
columnTemplate: (
createElement: HyperFunc,
props: ColumnTemplateProp,
additionalData?: any
) => {
const actions = ['sort', 'filter', 'settings'];
return createElement(
'div',
{ key: `header-${props.column.name}` },
actions.map((action, index) =>
createElement(
'button',
{
key: `action-${props.column.name}-${action}`,
class: `action-control action-${action}`,
},
action
)
)
);
},
},
]
```
---
# Header Properties
Source: https://rv-grid.com/guide/column/properties
# Header Properties
[Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular) [Type: ColPropertiesFunc](https://rv-grid.com/guide/types/TypeAlias.ColPropertiesFunc)
Attributes or settings applied to column headers, influencing their behavior and presentation, such as [width, visibility, and events](https://rv-grid.com/guide/types/TypeAlias.CellProps).
```ts
const columns: ColumnRegular[] = [{
name: 'Person name',
prop: 'name',
// apply this for custom properties
columnProperties: ({ prop }: ColumnRegular): CellProps => {
return {
style: {
color: 'red',
},
class: {
bank: true,
},
}
},
}]
```
---
# Readonly
Source: https://rv-grid.com/guide/column/readonly
# Readonly
[ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel)
[ReadOnlyFormat](https://rv-grid.com/guide/types/TypeAlias.ReadOnlyFormat)
To use the `readonly` property in RevoGrid, you can set it either as a boolean value or as a function that returns a boolean value based on the provided `ColumnDataSchemaModel`.
### Using `readonly` as a Boolean
If you want the entire column to be read-only, you can set the `readonly` property to `true` for that column.
```javascript
const columns = [
{
prop: 'name',
name: 'Name',
readonly: true, // This column is read-only
},
{
prop: 'age',
name: 'Age',
},
]
const data = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
]
```
### Using `readonly` as a Function
If you want to conditionally set the `readonly` property based on the column data, you can provide a function that returns a boolean value.
```javascript
const columns = [
{
prop: 'name',
name: 'Name',
readonly: (params) => {
// Make the cell read-only if the name is 'John'
return params.model.name === 'John'
},
},
{
prop: 'age',
name: 'Age',
},
]
const data = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
]
```
In this example, the `name` column will be read-only for rows where the `name` is 'John'. For other rows, it will be editable.
### Example with Both Approaches
Here is an example combining both approaches for different columns:
```javascript
const columns = [
{
prop: 'name',
name: 'Name',
readonly: true, // Entire column is read-only
},
{
prop: 'age',
name: 'Age',
readonly: (params) => {
// Make the cell read-only if the age is greater than 28
return params.model.age > 28
},
},
]
const data = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
]
```
### Complete Example in Context
Here’s how you might integrate this into a full RevoGrid component in a React application:
```js
const App = () => {
const columns = [
{
prop: 'name',
name: 'Name',
readonly: true, // Entire column is read-only
},
{
prop: 'age',
name: 'Age',
readonly: (params) => {
// Make the cell read-only if the age is greater than 28
return params.model.age > 28
},
},
]
const data = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
]
}
export default App
```
This example demonstrates how to configure columns to be read-only either entirely or based on specific conditions using RevoGrid's `readonly` property.
---
# Column Ordering
Source: https://rv-grid.com/guide/column/order
# Column Ordering
The Column Ordering plugin allows users to reorder columns through a simple drag-and-drop interface, providing enhanced control over grid layout. This feature can be enabled by setting the `canMoveColumns` property to `true`.
## Key Events:
- **`columndragstart`**: Triggered when a column drag operation starts. You can use this event to conditionally prevent certain columns from being moved. The event detail is the column definition being dragged.
- **`columndragmousemove`**: Fired during the drag operation, allowing you to track the movement of the column.
- **`beforecolumndragend`**: Fired before the drag operation is applied. This event is cancelable; call `event.preventDefault()` to reject the move.
- **`columndragend`**: Fired when the column drag operation is completed. Use `event.detail.columns` or `event.detail.order` to read and save the final column order for the affected viewport.
:::tip
`roworderchanged` is only for row drag-and-drop. Column drag-and-drop uses the `columndrag*` plugin events above.
:::
## Example Usage
Here’s an example of how to set up and use the Column Ordering plugin in RevoGrid:
```javascript
import { defineCustomElement } from '@revolist/revogrid/standalone';
defineCustomElement();
// Define your grid columns
const columns = [
{ name: 'ID', prop: 'id' },
{ name: 'Name', prop: 'name' },
{ name: 'Price', prop: 'price' }
];
// Initialize RevoGrid
const grid = document.querySelector('revo-grid');
if (grid) {
grid.source = [
{ id: 1, name: 'Apple', price: 1.2 },
{ id: 2, name: 'Banana', price: 0.5 },
{ id: 3, name: 'Cherry', price: 2.0 }
];
grid.columns = columns;
// Enable column movement
grid.canMoveColumns = true;
// Event listener to prevent certain columns from being moved
grid.addEventListener('columndragstart', (e) => {
const { detail } = e;
if (detail.prop === 'id') {
e.preventDefault(); // Prevent moving the 'ID' column
}
});
// Optional: validate the target before the move is applied
grid.addEventListener('beforecolumndragend', (e) => {
const { newItem, newPosition } = e.detail;
if (newItem?.prop === 'id' || newPosition.itemIndex === 0) {
e.preventDefault();
}
});
// Save the final order after the move is applied
grid.addEventListener('columndragend', (e) => {
const order = e.detail.columns.map(({ prop }) => prop);
localStorage.setItem('revogrid:column-order', JSON.stringify(order));
console.log('Column order changed in viewport:', e.detail.type, order);
});
}
```
## Customization and Control
In the example above:
- The `canMoveColumns` property is set to `true` to enable the column drag-and-drop feature.
- The `columndragstart` event listener checks if the column being dragged is the 'ID' column. If it is, the drag operation is prevented by calling `e.preventDefault()`.
- The `beforecolumndragend` event can cancel a specific drop target before the internal column order is updated.
- The `columndragend` event runs after the internal order is updated. Use `event.detail.columns` to get the reordered columns for the affected viewport and persist them to local storage, user settings, or your backend.
## Persisting and Restoring Order
A common pattern is to save only the `prop` sequence from `columndragend.detail.columns`, then sort your application-level column definitions before assigning them back to the grid on the next load.
```ts
const savedOrder = JSON.parse(
localStorage.getItem('revogrid:column-order') || '[]',
) as string[];
const orderIndex = new Map(savedOrder.map((prop, index) => [prop, index]));
grid.columns = [...columns].sort((a, b) => {
const left = orderIndex.get(String(a.prop)) ?? Number.MAX_SAFE_INTEGER;
const right = orderIndex.get(String(b.prop)) ?? Number.MAX_SAFE_INTEGER;
return left - right;
});
```
For pinned columns, `columndragend.detail.type` identifies the affected column viewport: `rgCol`, `colPinStart`, or `colPinEnd`. If your application stores pinned and regular column order separately, use that value to update only the affected region.
---
# Pin/Freeze (Fixed columns)
Source: https://rv-grid.com/guide/column/pin
# Pin/Freeze (Fixed columns)
[Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular) [Type: DimensionColPin](https://rv-grid.com/guide/types/TypeAlias.DimensionColPin)
:::warning
Be aware that pinning columns and rows introduces virtual indexes to the grid. Please read more in the [Viewports section](https://rv-grid.com/guide/viewports).
:::
Allows columns to be fixed or "pinned" to one side of the grid, remaining visible as the user scrolls horizontally through other columns.
``` ts
const columns = [
{ name: 'First Name', prop: 'firstName', },
{ name: 'Status', prop: 'status', pin: 'colPinStart', },
{ name: 'Age', prop: 'age', pin: 'colPinEnd', },
];
```
## JavaScript Column Pin and Freeze
:::preview #demo-overview .rv-overview :path /demo/js/js.column.pin.example
:::
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/js/js.column.pin.example.ts)
::: code-group
<<< @/demo/js/js.column.pin.example.ts#snippet
:::
---
# Column Grouping
Source: https://rv-grid.com/guide/column/grouping
# Column Grouping
[Interface: ColumnGrouping](https://rv-grid.com/guide/types/Interface.ColumnGrouping)
Column grouping creates stacked headers by placing related columns under a shared parent header. Use it when several fields belong to the same business concept, for example `Personal` details with `First Name`, `Last Name`, and `Age` below it.
Groups are declared directly in the `columns` array. A regular column has a `prop`; a grouped column has `children`. Grouped columns can be nested, so the header can have as many levels as your layout needs.
## JavaScript Column Grouping
## Basic structure
```ts
import type { ColumnGrouping, ColumnRegular } from '@revolist/revogrid'
const columns: (ColumnGrouping | ColumnRegular)[] = [
{
name: 'Personal',
children: [
{ name: 'First Name', prop: 'firstName' },
{ name: 'Last Name', prop: 'lastName' },
],
},
{ name: 'Project', prop: 'project' },
]
```
In this example `Personal` is only a header group. The leaf columns, `First Name` and `Last Name`, are still the columns bound to row data.
## Nested groups
Use nested `children` arrays when a header needs more than one grouping level. RevoGrid calculates the header depth from the column tree and aligns regular columns with grouped columns automatically.
<<< @/demo/js/js.column.group.example.ts#columns
## When to use column groups
- Group related fields so wide datasets are easier to scan.
- Create multi-level headers for reports, financial tables, schedules, and operational dashboards.
- Keep column definitions declarative instead of manually composing header rows.
- Combine groups with regular column features such as sizing, sorting, pinning, templates, and filtering on the leaf columns.
## Notes
- A grouped column should use `children`; a leaf column should use `prop`.
- Sorting, filtering, editing, and data mapping apply to leaf columns.
- Header templates can still be used on regular leaf columns. For group header customization, use the group/header render hooks exposed by the header API.
- Column groups are a core feature and work in Community, Pro Lite, and Pro Advanced.
## Pro grouping features
RevoGrid Pro extends grouping from static headers into interactive analysis, layout control, and grouped summaries.
### Column collapse and expand
[Column Collapse & Expand](https://rv-grid.com/pro) lets users drill down through grouped columns by collapsing less relevant branches and expanding them again when detail is needed. It is designed for wide grouped datasets where users need a compact working view without removing the underlying column structure.
### Column hide
[Column Hide](https://rv-grid.com/pro) can be used with grouped layouts to create focused views of a dataset. Hide low-priority fields while keeping the remaining grouped headers readable and aligned.
### Row grouping drag and drop
[Row Grouping Drag and Drop](https://rv-grid.com/pro) adds an interactive grouping panel where users can drag columns to group rows by one or more fields. Use it when grouping should be controlled by the user at runtime instead of being fixed in the grid configuration.
### Grouping aggregation
[Grouping Aggregation](https://rv-grid.com/pro) adds summary values to grouped data, such as sum, average, count, min, or max. It is useful for grouped reports, financial summaries, and operational dashboards where each group needs an immediate total or metric.
### Pivot row and column grouping
[Pivot Table](https://rv-grid.com/pivot) builds analytical row and column groups from dimensions and measures. It adds generated column groups, hierarchical rows, subtotals, grand totals, drill-down state, and grouped aggregate values for OLAP-style reporting.
---
# RevoGrid Column Types and Column Formats
Source: https://rv-grid.com/guide/column/types
Description: Configure reusable RevoGrid column types for string, number, select, date, custom editors, cell templates, parsers, and shared data grid formatting.
# Column Types and Formats
Column types let you package column behavior once and reuse it across your grid. A type can define formatting, sizing, read-only rules, custom editors, cell templates, parsers, sorting behavior, and any other reusable column option.
Use column types when several columns should behave the same way, or when a column needs a richer editor such as a number formatter, select dropdown, or date picker.
## How column types work
RevoGrid exposes two related APIs:
- `columnTypes` is a map of reusable type definitions registered on the grid.
- `columnType` is the name used by a column to apply one of those definitions.
Column settings are merged with the selected type. If the same option exists in both places, the column definition can override the shared type for that column.
[Type: ColumnTypes](https://rv-grid.com/guide/types/TypeAlias.ColumnTypes)
[Interface: ColumnType](https://rv-grid.com/guide/types/Interface.ColumnType)
[Interface: ColumnRegular](https://rv-grid.com/guide/types/Interface.ColumnRegular)
```ts
const grid = document.querySelector('revo-grid')
grid.columnTypes = {
money: {
size: 140,
readonly: false,
cellTemplate: (createElement, props) => {
const value = Number(props.model[props.prop] ?? 0)
return createElement(
'span',
{ class: { 'money-cell': true, 'money-negative': value < 0 } },
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(value)
)
},
cellParser: (model, column) => Number(model[column.prop] ?? 0),
},
}
grid.columns = [
{ prop: 'revenue', name: 'Revenue', columnType: 'money' },
{ prop: 'cost', name: 'Cost', columnType: 'money', size: 110 },
]
```
## Built-in and plugin column formats
The string format is available by default. Number, select, and date formats are distributed as optional packages so applications only ship the editors and formatters they actually use.
| Format | Package | Best for |
| --- | --- | --- |
| [String](#string) | Built in | Plain text, IDs, labels, and default editable cells |
| [Number](#number) | `@revolist/revogrid-column-numeral` | Numeric display, thousands separators, currency-like formatting |
| [Select Dropdown](#select-dropdown) | `@revolist/revogrid-column-select` | Controlled choices, status values, lookup lists |
| [Date](#date) | `@revolist/revogrid-column-date` | Date input, calendar picking, date strings |
## When to create a custom column type
Create a custom type when the same column behavior appears in multiple places:
- a currency or percentage format shared by many numeric columns
- a reusable status style with custom classes
- a read-only system field preset
- a custom editor used by multiple columns
- a parser that keeps filtering and sorting aligned with displayed values
For one-off rendering, configure the column directly instead. See [Custom Cell Formats](https://rv-grid.com/guide/cell/custom-formats), [Cell Renderer](https://rv-grid.com/guide/cell/renderer), and [Cell Editor](https://rv-grid.com/guide/cell/editor).
## Register optional column type packages
Optional column packages follow the same pattern:
1. Install the package.
2. Import the type plugin.
3. Register it in `columnTypes`.
4. Reference it from a column with `columnType`.
```ts
import NumberColumnType from '@revolist/revogrid-column-numeral'
const columnTypes = {
numeric: new NumberColumnType('0,0'),
}
const columns = [
{ prop: 'quantity', name: 'Quantity', columnType: 'numeric' },
]
```
Framework wrappers use the same data shape. Pass `columns`, `source`, and `columnTypes` through your framework binding, or assign them directly to the `` element in plain JavaScript.
## Available column formats
### String
String is the default RevoGrid column format. Use it for plain text, identifiers, labels, and any editable cell that does not need a specialized editor.
No package or registration is required:
```ts
const columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'email', name: 'Email' },
]
```
Values are read as text for display. If a column needs custom rendering, validation, parsing, or editing behavior, define those options directly on the column or move them into a reusable `columnTypes` preset.
### Number
The number column type adds numeric formatting through the [revogrid-column-numeral](https://github.com/revolist/revogrid-column-numeral) package, based on [numeraljs](http://numeraljs.com). Use it for quantities, totals, prices, percentages, and other numeric values that should keep a consistent display format.
The source value should be numeric or safely convertible to a number. The formatter controls how the value appears in the cell.
#### Installation
::: code-group
```npm
npm i @revolist/revogrid-column-numeral
```
```pnpm
pnpm add @revolist/revogrid-column-numeral
```
```yarn
yarn add @revolist/revogrid-column-numeral
```
```bun
bun add @revolist/revogrid-column-numeral
```
:::
#### Basic usage
```js
import NumberColumnType from '@revolist/revogrid-column-numeral' // import library
const plugin = { numeric: new NumberColumnType('0,0') } // create plugin entity
const columns = [{ prop: 'num', columnType: 'numeric' }] // define column type
const rows = [{ num: 1000 }]
const grid = document.querySelector('revo-grid')
grid.columnTypes = plugin
grid.source = rows
grid.columns = columns
// '1,000'
```
#### Format examples
```ts
const columnTypes = {
integer: new NumberColumnType('0,0'),
decimal: new NumberColumnType('0,0.00'),
percent: new NumberColumnType('0.0%'),
}
const columns = [
{ prop: 'orders', name: 'Orders', columnType: 'integer' },
{ prop: 'revenue', name: 'Revenue', columnType: 'decimal' },
{ prop: 'conversion', name: 'Conversion', columnType: 'percent' },
]
```
For more formatting options, check the [plugin page](https://github.com/revolist/revogrid-column-numeral) and [numeraljs](http://numeraljs.com).
### Select Dropdown
The select column type adds a dropdown editor through the [revogrid-column-select](https://github.com/revolist/RevoGrid-column-select) package, based on [revo-dropdown](https://github.com/revolist/revodropdown).
Use it when users should choose from a controlled list of values, such as statuses, departments, categories, countries, or lookup table entries.
Dropdown options can be represented as strings or objects. When using objects, configure `labelKey` and `valueKey` so the editor knows what to display and what to store.
#### Installation
::: code-group
```npm
npm i @revolist/revogrid-column-select
```
```pnpm
pnpm add @revolist/revogrid-column-select
```
```yarn
yarn add @revolist/revogrid-column-select
```
```bun
bun add @revolist/revogrid-column-select
```
:::
#### Basic usage
1. Import the select column type.
2. Define the dropdown source.
3. Register the type in `columnTypes`.
4. Set `columnType: 'select'` on the column.
```js
// do Select class import
import SelectTypePlugin from '@revolist/revogrid-column-select'
const dropdown = {
labelKey: 'label',
valueKey: 'value',
source: [
{ label: 'According', value: 'a' },
{ label: 'Over', value: 'b' },
{ label: 'Source', value: 's' },
],
}
const columns = [
{
...dropdown,
prop: 'name',
columnType: 'select', // column type specified as 'select'
},
]
const rows = [{ name: 'New item' }, { name: 'New item 2' }]
// register column type
const plugin = { select: new SelectTypePlugin() }
// apply data to grid per your framework approach
```
#### Option shape
```ts
const dropdown = {
labelKey: 'label',
valueKey: 'value',
source: [
{ label: 'Draft', value: 'draft' },
{ label: 'Approved', value: 'approved' },
{ label: 'Archived', value: 'archived' },
],
}
```
Use the object form when the visible label and stored value should differ.
#### Synchronize cell and dropdown templates
Set `syncCellTemplate` to `true` when dropdown options should reuse the
resolved cell template. This is opt-in; without the flag, options keep their
existing text-only rendering. Object option fields are available on the
synthetic row model passed to the cell template, which is useful for avatars,
badges, and other metadata-driven renderers.
```ts
const ownerType = new SelectTypePlugin()
ownerType.cellTemplate = ownerCellTemplate
ownerType.syncCellTemplate = true
const columnTypes = { ownerSelect: ownerType }
const columns = [
{
prop: 'owner',
columnType: 'ownerSelect',
labelKey: 'name',
valueKey: 'name',
source: [
{ name: 'Maya Chen', avatarIndex: 1 },
{ name: 'Elias Novak', avatarIndex: 2 },
],
},
]
```
If the column also provides an explicit dropdown `template`, that template
takes precedence.
#### Dynamic source
`source` can be a synchronous function when options depend on the current row
or on external state passed through `additionalData`.
```ts
const columns = [
{
prop: 'city',
columnType: 'select',
labelKey: 'label',
valueKey: 'value',
source: ({ model, additionalData }) =>
additionalData.citiesByCountry[model.country] ?? [],
},
]
```
The resolver receives the current cell model, prop, column, indexes, and
`additionalData`. Async loading is not supported by this API.
### Date
The date column type adds a calendar editor through the [revogrid-column-date](https://github.com/revolist/revogrid-column-date) package, based on [duetds-date-picker](https://github.com/duetds/date-picker).
Use it for date strings or date values that should be edited with a date picker instead of plain text input.
You can pass [duetds-date-picker](https://github.com/duetds/date-picker) properties through the column definition:
```js
const columns = [
{
prop: 'birthdate',
columnType: 'date',
direction: 'left',
required: 'true',
valueAsDate: 'true',
},
]
```
#### Installation
::: code-group
```npm
npm i @revolist/revogrid-column-date
```
```pnpm
pnpm add @revolist/revogrid-column-date
```
```yarn
yarn add @revolist/revogrid-column-date
```
```bun
bun add @revolist/revogrid-column-date
```
:::
#### Basic usage
1. Import the date column type.
2. Register it in `columnTypes`.
3. Set `columnType: 'date'` on date columns.
4. Pass picker options on the column when needed.
```js
// do import
import Plugin from '@revolist/revogrid-column-date'
const columns = [{ prop: 'birthdate', columnType: 'date' }]
const rows = [{ birthdate: '2020-08-24' }, { birthdate: '2022-08-24' }]
// register column type
const columnTypes = { date: new Plugin() }
// apply data to grid per your framework approach
```
Keep the date value format consistent across the column. If your application stores dates in a different shape than the editor displays, normalize the value before assigning `source` or handle conversion in your save workflow.
# Date Column Demo
[](https://codesandbox.io/p/sandbox/rg-date-standalone-jwwwd8?file=%2Fsrc%2Findex.ts%3A27%2C62)
## RevoGrid Pro formats
Available for richer data-entry, validation, and visualization workflows. Most Pro formats are registered through the same `columnTypes` pattern shown above, then applied with `columnType` on the target column.
### Checkbox editor
Use a checkbox editor for boolean flags, approvals, task completion, row-level toggles, and other true/false values. It combines the renderer and editor into one compact cell interaction.
### Slider editor
Use a slider editor for bounded numeric values such as scores, progress, priority, confidence, utilization, or percentage-like input where users need quick visual adjustment.
### Counter editor
Use a counter editor for quantities, capacity, step-based values, and fast increment/decrement editing. It works well when values change in predictable steps.
### Timeline editor
Use a timeline editor for date ranges, schedules, delivery windows, and project timelines. It gives users a visual date-range editing experience inside the grid.
### Progress line
Use a progress line to show completion, utilization, SLA progress, budget usage, or any proportional value in a compact visual format.
### Progress line with value
Use a progress line with value when users need both the visual progress bar and the exact readable number in the same cell.
### Sparkline
Use a sparkline to show compact trends for time-series values, historical metrics, activity, or performance movement without opening a separate chart.
### Bar chart
Use an inline bar chart for ranking, proportional comparison, and quick scanning of numeric values across many rows.
### Timeline
Use a timeline format to display duration, phase, start/end positioning, or schedule context directly in grid cells.
### Rating star
Use rating stars for reviews, quality scores, priority levels, satisfaction, or any small fixed-range rating.
### Badge
Use badges for statuses, categories, severities, tags, workflow states, and other short labels that benefit from consistent visual treatment.
### Change
Use a change format for deltas, gain/loss indicators, period-over-period movement, and positive/negative value changes.
### Thumbs
Use thumbs for sentiment, approval, pass/fail, and quick feedback values.
### Pie chart
Use an inline pie chart for part-to-whole values, compact distributions, and proportional breakdowns.
### Heat and cold map
Use heat and cold maps to highlight value intensity, outliers, risk, performance bands, and low/high ranges with color.
### Conditional formatting
Use conditional formatting for rule-based styles such as thresholds, alerts, exceptions, and state-dependent highlighting.
### Multi-cell formatting
Use multi-cell formatting when different cells in the same column need different renderers, editors, or styles based on row data or custom conditions.
### Reference data
Use reference data when the stored value is an ID, code, or key, but the user should see a readable label from a lookup source.
### Connected fields
Use connected fields when values in one column depend on another column, or when edits should update linked cell behavior across the row.
### Cell validation
Use cell validation to highlight invalid cells and prevent bad edits from becoming part of the data set.
### Input validation
Use input validation to validate editor input before committing it to the grid, especially for constrained values, required fields, and business rules.
See [RevoGrid Pro](https://rv-grid.com/pro/) and the [Feature Comparison](https://rv-grid.com/pro/feature-table) for plan availability and demos.
## Practical tips
- Register `columnTypes` before assigning columns when possible, especially during initial grid setup.
- Keep the data shape stable: `prop` must match a key in the row object.
- Use `cellParser` when filtering should operate on a normalized value instead of formatted text.
- Use column-level options to override a shared type for a single column.
- Keep optional plugins out of the bundle until you need their editors or formatters.
## Troubleshooting
If a type does not apply, check that the key in `columnTypes` exactly matches the column `columnType` value.
If a plugin editor does not open, confirm that the package is installed, imported, and registered as an instance where the plugin expects one, for example `new NumberColumnType('0,0')`.
If displayed values and filtering behave differently, add a `cellParser` to return the value that filter logic should use.
Check the [live demos](https://rv-grid.com/demo/) for working grid examples, or use [Column Configuration](https://rv-grid.com/guide/column/) for the full list of column options.
---
# Column Stretching in Data Grid
Source: https://rv-grid.com/guide/column/stretch
# Column Stretching in Data Grid
The Column Stretch feature allows you to automatically expand the last column ([or any, or all columns](https://rv-grid.com/guide/column/stretch.pro)) to fill any remaining space in your grid. This ensures that your grid fully utilizes the available width, providing a more polished and professional appearance.
## Enabling Column Stretch
To enable column stretching, simply set the `stretch` attribute to `"true"`. This will activate the feature, causing the last column to stretch and fill any unused space in the grid.
### Example Usage
Here’s how to enable column stretching:
```html
```
### How It Works
With the `stretch` attribute enabled:
- The last column will automatically adjust its width to fill the remaining space in the grid.
- This feature is particularly useful when the total width of your columns doesn't match the width of the grid, ensuring that there are no gaps at the end.
### Benefits of Column Stretching
- **Improved Aesthetics**: The grid appears fully utilized, eliminating any unnecessary white space.
- **Responsive Design**: Automatically adapts to different screen sizes or container widths, making your grid more flexible.
- **Simple Implementation**: Easily enable this feature with a single attribute, requiring no complex configuration.
## Conclusion
The Column Stretch feature is a simple yet effective way to enhance the layout of your grid by ensuring the last column always fills the available space. By using the `stretch="true"` attribute, you can create grids that look clean, professional, and responsive with minimal effort.
---
# Data Grid Cell Configuration
Source: https://rv-grid.com/guide/cell
Description: Set up Cell Configuration in Data Grid.
The intersection point of a row and a column in the grid, capable of displaying and editing data. A cell can have custom renderers and editors, which are tightly coupled with the column properties.
You can [customize cells using templates](https://rv-grid.com/guide/cell/renderer) to change their appearance or behavior.
## Cell Properties [Type: PropertiesFunc](https://rv-grid.com/guide/types/TypeAlias.PropertiesFunc)
What are cell properties in RevoGrid. You can add various properties to cells, including tags, styles, classes, and events like `onClick`.
## Adding Custom Properties
You can customize cells by defining properties within the `cellProperties` function. This function allows you to dynamically assign styles, classes, data attributes, and events based on the cell's data.
### Example
Here's an example of how to use `cellProperties` to add custom styles, classes, data attributes, and events to cells:
```js
const columns = [{
name: 'Person Name',
prop: 'name',
// Apply custom properties
cellProperties: ({prop, model, data, column}) => {
return {
// Custom styles
style: {
color: model[prop] === 'John Doe' ? 'red' : 'black'
},
// Custom classes
class: {
'bank': data.isBankCustomer,
'vip': data.isVIP
},
// Custom events
onClick: (event) => {
console.log(`Cell clicked: ${model[prop]}`);
},
// Custom data attribute
'data-tooltip': model[prop]
};
},
}];
const items = [
{ name: 'John Doe', isBankCustomer: true, isVIP: false },
{ name: 'Jane Smith', isBankCustomer: false, isVIP: true }
];
// Applying the columns and data source to the grid
grid.columns = columns;
grid.source = items;
```
## Advanced Cell Features
RevoGrid offers advanced cell features, including:
- [Formula Support](https://rv-grid.com/guide/cell/formula)
- [Cell Merge](https://rv-grid.com/guide/cell/merge)
- [Other Features](https://rv-grid.com/pro)
---
# RevoGrid Cell Renderer
Source: https://rv-grid.com/guide/cell/renderer
Description: Use RevoGrid cell templates to render custom cell content safely and efficiently across JavaScript and framework integrations.
# Cell renderer [Interface: CellTemplate](https://rv-grid.com/guide/types/Interface.CellTemplate) [Interface: CellTemplateProp](https://rv-grid.com/guide/types/Interface.CellTemplateProp)
This article explains how to use a [custom cell function](https://rv-grid.com/guide/types/Interface.CellTemplate) to display HTML content in a cell.
Alternatively, you can use [predefined column types](https://rv-grid.com/guide/column/types).
> [!WARNING]
> Remember to escape any HTML code that could be used for XSS attacks.
:::tip
RevoGrid's [API](https://rv-grid.com/guide/api/revoGrid) is consistent across all major frameworks. Transfer your experience and knowledge from one framework to another.
:::
> [!TIP]
> Use [JSX](https://rv-grid.com/guide/jsx.template) to simplify your code and render HTML content.
```ts
const columns: ColumnRegular[] = [
{
name: 'Person name',
prop: 'name',
cellTemplate: (
createElement: HyperFunc,
props: CellTemplateProp,
additionalData?: any
) => {
return createElement(
'span',
{
style: {
color: 'red',
},
},
props.model[props.prop]
)
},
},
]
```
## Using Keys in Cell Templates
> [!IMPORTANT]
> **Keys are essential for VNode reconciliation.** When rendering lists or dynamic content, always provide unique keys to help the virtual DOM accurately identify, track, and update nodes. Use keys thoughtfully, as incorrect usage can lead to inefficient updates or unexpected behavior.
### Why Keys Matter
Keys allow the virtual DOM to:
- **Identify unique nodes** - Distinguish between different items even when content is similar
- **Optimize updates** - Efficiently update only the nodes that have changed
- **Preserve state** - Maintain component state when items are reordered or filtered
### Basic Key Usage
When rendering multiple child elements, provide unique keys:
```ts
const columns: ColumnRegular[] = [
{
name: 'Tags',
prop: 'tags',
cellTemplate: (
createElement: HyperFunc,
props: CellTemplateProp,
additionalData?: any
) => {
const tags = props.model[props.prop] || [];
return createElement(
'div',
null,
tags.map((tag: any, index: number) =>
createElement(
'span',
{
key: tag.id || `tag-${props.rowIndex}-${index}`,
class: 'tag',
},
tag.label
)
)
);
},
},
]
```
### Using Keys with Row and Column Identifiers
For cells that may be reordered or filtered, combine row and column identifiers:
```ts
const columns: ColumnRegular[] = [
{
name: 'Status',
prop: 'status',
cellTemplate: (
createElement: HyperFunc,
props: CellTemplateProp,
additionalData?: any
) => {
return createElement(
'div',
{
key: `cell-${props.rowIndex}-${props.colIndex}`,
class: `status-${props.model[props.prop]}`,
},
props.model[props.prop]
);
},
},
]
```
### Best Practices
1. **Use stable identifiers** - Prefer IDs from your data model over array indices when possible
2. **Combine identifiers** - For cells, combine `rowIndex` and `colIndex` or use a unique row ID
3. **Keep keys consistent** - The same data item should always have the same key across renders
4. **Avoid random keys** - Never use `Math.random()` or similar as keys
### Example: Complex Cell with Multiple Elements
```ts
const columns: ColumnRegular[] = [
{
name: 'Details',
prop: 'details',
cellTemplate: (
createElement: HyperFunc,
props: CellTemplateProp,
additionalData?: any
) => {
const details = props.model[props.prop] || [];
const cellKey = `details-${props.rowIndex}-${props.colIndex}`;
return createElement(
'div',
{ key: cellKey },
[
createElement('span', { key: `${cellKey}-title` }, props.model.name),
createElement(
'ul',
{ key: `${cellKey}-list` },
details.map((detail: any, index: number) =>
createElement(
'li',
{ key: detail.id || `${cellKey}-item-${index}` },
detail.text
)
)
)
]
);
},
},
]
```
## Related Pro features
If you need richer visual cells such as charts, conditional formatting, heatmaps, or multi-renderer patterns, continue with [RevoGrid Pro](https://rv-grid.com/pro/) and [Feature Comparison](https://rv-grid.com/pro/feature-table).
---
# RevoGrid Custom Cell Formats
Source: https://rv-grid.com/guide/cell/custom-formats
Description: Create custom RevoGrid cell formats with cell templates, cell properties, parsers, and reusable column types.
# Custom Cell Formats
Custom cell formats define how a value should look, behave, and be interpreted inside the grid. For a single column, configure formatting directly on the column definition. For reusable formats, define a `columnTypes` preset and reference it from any column with `columnType`.
Use [Column Formats](https://rv-grid.com/guide/column/types) when you want to define custom formats per column or reuse the same format across many columns and cells.
## Format a single column
Use `cellTemplate` when the display value needs custom markup or logic:
```ts
const columns = [
{
name: 'Total',
prop: 'total',
cellTemplate: (createElement, props) => {
const value = Number(props.model[props.prop] ?? 0)
return createElement(
'span',
{
class: {
'amount-positive': value >= 0,
'amount-negative': value < 0,
},
},
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(value)
)
},
},
]
```
Use `cellProperties` when the original value can stay as text, but the cell needs classes, styles, data attributes, or events:
```ts
const columns = [
{
name: 'Status',
prop: 'status',
cellProperties: ({ model, prop }) => ({
class: {
'status-cell': true,
'status-done': model[prop] === 'Done',
'status-blocked': model[prop] === 'Blocked',
},
'data-status': model[prop],
}),
},
]
```
## Reuse a format with `columnTypes`
Define a format once in `grid.columnTypes`, then use `columnType` on every column that should inherit it:
```ts
const currencyFormat = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
})
grid.columnTypes = {
money: {
size: 140,
cellTemplate: (createElement, props) => {
const value = Number(props.model[props.prop] ?? 0)
return createElement(
'span',
{
class: {
'money-cell': true,
'money-negative': value < 0,
},
},
currencyFormat.format(value)
)
},
cellParser: (model, column) => Number(model[column.prop] ?? 0),
},
}
grid.columns = [
{ name: 'Revenue', prop: 'revenue', columnType: 'money' },
{ name: 'Cost', prop: 'cost', columnType: 'money' },
]
```
Column settings override inherited `columnTypes` settings, so you can keep the shared format and adjust a specific column:
```ts
grid.columns = [
{ name: 'Revenue', prop: 'revenue', columnType: 'money' },
{ name: 'Cost', prop: 'cost', columnType: 'money', size: 110 },
]
```
## Choosing the right option
- Use `cellProperties` for classes, styles, data attributes, and event handlers.
- Use `cellTemplate` for custom rendered content.
- Use `cellParser` when filtering or data operations need a parsed value that differs from the displayed value.
- Use `columnTypes` when the same format should be shared across multiple columns.
See also [Cell Renderer](https://rv-grid.com/guide/cell/renderer), [Cell Editor](https://rv-grid.com/guide/cell/editor), and [Column Formats](https://rv-grid.com/guide/column/types).
---
# Data Grid Cell Editors
Source: https://rv-grid.com/guide/cell/editor
Description: Build custom RevoGrid cell editors with render functions, save and close callbacks, editor lifecycle hooks, and TypeScript examples.
# Cell editor in Data Grid
`RevoGrid` provides a way to define your own editors. Or you can use [predefined column types](https://rv-grid.com/guide/column/types).
In order to do so you have to define your class with render method.
## As a Function
```js
function TextEditor(dataSchema, saveCallback, closeCallback) {
return {
element: null, // will be setup up after render
editCell: null, // will be setup up after render
/**
* required, define custom component structure
* @param createElement: (tagName: string, properties?: object, value?: any, children: Array) => VNode
*/
render(createElement) {
return createElement('input');
},
componentDidRender() {}, // optional, called after component rendered
disconnectedCallback() {}, // optional, called after component destroyed
};
};
```
## As a Class
```ts
class TextEditor {
public element: Element|null = null;
public editCell: EditCell|null = null;
/**
* @dataSchema: {ColumnDataSchemaModel} - data
* @editCallback: { (val) => void } - callback for finishing edit
*/
constructor(
public dataSchema: ColumnDataSchemaModel,
saveCallback: (value: any) => void,
closeCallback: () => void
) {}
// optional, called after editor rendered
componentDidRender() {}
// optional, called after editor destroyed
disconnectedCallback() {}
/**
* required, define custom component structure
* @param createElement: (tagName: string, properties?: object, value?: any, children: Array) => VNode
*/
render(createComponent: HyperFunc) {
return createComponent('input');
}
/**
* Optional method to get the current value from the editor
* Called during auto-save process
*/
getValue() {
// Return the current value from your editor
return this.element?.value;
}
/**
* Optional method called before auto-save is performed
* Return false to prevent the auto-save
* @param value The current value to be saved
*/
beforeAutoSave(value: any): boolean {
// Return false to prevent save, true to allow
return true;
}
/**
* Optional method called before the editor is disconnected
* Use this to cleanup any resources
*/
beforeDisconnect() {
// Cleanup any resources before editor is destroyed
}
}
```
## Editor Lifecycle and Save Behavior
The editor component includes several important methods for handling save operations and lifecycle events:
### Auto-Save Process
When auto-save is triggered (either through `saveOnClose` or programmatically):
1. The editor calls `getValue()` to retrieve the current value
2. If `beforeAutoSave()` is defined, it's called with the value:
- Return `false` to prevent the save
- Return `true` (or undefined) to allow the save
3. If save is allowed, the value is saved and the editor closes
### Save Options
You can control save behavior through:
- `saveOnClose` property - When true, editor attempts to save on close
- Manual save - Call save callback directly from your editor
- Cancel changes - Prevent save on close by calling `cancelChanges()`
## Use editor in the grid
```js
const columns = [{
name: 'Person',
prop: 'name',
// define editor name
editor: 'select',
}];
const grid = div.querySelector('revo-grid');
// define editor component and name
grid.editors = {
'select': customSelect
};
```
---
# Data & Rows in Data Grids
Source: https://rv-grid.com/guide/row
# Data & Rows in Data Grids
A horizontal line in the grid representing a single data item from the source.
RevoGrid offers extensive capabilities for managing rows and the data they contain. From customizing row appearances with class bindings to handling complex data structures, RevoGrid provides the tools you need to create dynamic and responsive data grids.
## Row Class Binding
Row class binding allows you to dynamically apply CSS classes to individual rows based on the data they contain. This feature is useful for visually distinguishing rows that meet certain criteria, such as highlighting rows with specific statuses or applying alternate row colors.
### Using Row Class Binding
To bind a CSS class to rows, you first need to define a property in your data source that will determine the row's class.
You then use the `rowClass` attribute to tell RevoGrid which property to use for this purpose.
### Example: Applying Row Classes
Here’s an example that demonstrates how to apply different CSS classes to rows based on the data:
```tsx
// Define columns
const columns = [{
name: 'Person',
prop: 'name'
}];
// Define data source with row classes
const source = [
{ name: 'Steve', myRowClass: 'blue' },
{ name: 'John', myRowClass: 'green' }
];
// Render RevoGrid with row class binding
return '';
```
In this example:
- The `myRowClass` property in the data source determines the CSS class applied to each row.
- The `rowClass="myRowClass"` attribute in the RevoGrid component binds the `myRowClass` property to the rows, causing the grid to render rows with the corresponding classes.
### Customizing Row Styles
You can define the styles for these classes in your CSS:
```css
.blue {
background-color: lightblue;
}
.green {
background-color: lightgreen;
}
```
With these styles applied, rows with `myRowClass: 'blue'` will have a light blue background, and rows with `myRowClass: 'green'` will have a light green background.
## Handling Complex Row Data
RevoGrid can handle complex data structures, allowing you to manage rows that contain nested data, custom templates, or dynamic content. This flexibility is essential for creating grids that need to display diverse data types or require custom rendering logic.
If your data contains nested objects or arrays, you can still bind this data to your grid's rows. Here’s an example:
```tsx
const columns = [{
name: 'Person',
prop: 'name'
}, {
name: 'Details',
prop: 'details',
cellTemplate: (h, data) => {
return h('span', `Age: ${data.value.age}`);
}
}];
const source = [
{ name: 'Steve', details: { age: 30 }, myRowClass: 'blue' },
{ name: 'John', details: { age: 25 }, myRowClass: 'green' }
];
return '';
```
In this example:
- The `details.age` property accesses nested data within the `details` object for each row.
- RevoGrid will correctly render the `age` property from the nested `details` object in the grid.
## Managing Row Visibility
You may also want to manage the visibility of certain rows based on specific conditions. RevoGrid allows you to easily show or hide rows programmatically.
```tsx
const grid = document.querySelector('revo-grid');
// Hide rows where the name is 'John'
const filteredSource = source.filter(row => row.name !== 'John');
grid.source = filteredSource;
```
In this example:
- The grid's data source is filtered to exclude rows where the `name` is 'John'.
- The grid is then updated to display only the remaining rows.
### Trimmed Rows
**Description:**
The **Trimmed Rows** feature enables selective hiding of rows from the main dataset using physical `rgRow` indexes. By defining `trimmedRows` as a record of row indexes with boolean values, you can dynamically control which rows are visible in the grid. This is particularly useful for managing large datasets, where certain rows can be hidden based on conditions or user interactions, enhancing both performance and usability.
**Example Usage:**
```tsx
const grid = document.querySelector('revo-grid');
// Define rows to be hidden
const trimmedRows = {
1: true, // Hides the row with index 1
5: true // Hides the row with index 5
};
// Apply trimmed rows to the grid
grid.trimmedRows = trimmedRows;
```
**Explanation:**
- **`trimmedRows`**: A record where each key represents the index of a row to hide (`true` indicates the row is hidden).
- **Dynamic Visibility**: Adjust which rows are visible by updating the `trimmedRows` record as needed.
## Odd Row Highlighting
The [`RowOddPlugin`](https://rv-grid.com/guide/row/odd.pro) allows you to automatically highlight odd-numbered rows in your data grid, enhancing the visual clarity and readability of your data.
## Master Rows
The [`MasterRowsPlugin`](https://rv-grid.com/guide/row/master.pro) enables expandable rows within the grid, allowing you to display detailed or hierarchical data for each row. This is ideal for presenting nested information such as sub-rows, additional details, or hierarchical structures.
**Benefits:**
- **Performance Optimization**: Reduces the amount of visible data, which can enhance grid performance.
- **Improved Usability**: Allows for better management of large datasets by hiding irrelevant or unneeded rows.
## Related guides
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Understanding Viewports](https://rv-grid.com/guide/viewports)
## Related Pro features
Need more row-focused workflows such as row select, row autosize, row order, transpose, or master-detail patterns? Continue with [RevoGrid Pro](https://rv-grid.com/pro/) and [Feature Comparison](https://rv-grid.com/pro/feature-table).
---
# Row Resizing in JavaScript Data Grid
Source: https://rv-grid.com/guide/row/resize
Description: Let users resize rows from row-header or full-row edges, configure height limits, and respond to resize lifecycle events.
Row resizing is an opt-in Core feature. Set the `resizeRow` grid property to let users drag the bottom edge of a row and change its height.
Completed sizes are stored through the grid's row-definition pipeline. A resized height therefore stays attached to its physical source row when filtering or sorting changes the visible row order.
## Resize from row headers
Set `resizeRow` and `rowHeaders` to `true` to display a resize edge at the bottom of each row header:
```js
const grid = document.querySelector('revo-grid');
grid.rowHeaders = true;
grid.resizeRow = true;
```
The boolean form uses the default minimum height of `20px` and has no maximum height.
For static HTML, the boolean option can also be enabled with attributes:
```html
```
## Resize from the full row edge
Pass a configuration object with `fullRow: true` to make the resize edge available across rendered data rows. Users can then resize from the bottom edge of a row without requiring row headers.
```js
const grid = document.querySelector('revo-grid');
grid.resizeRow = {
fullRow: true,
};
```
`fullRow` extends the edge target across the row; the row body remains available for selection, editing, and other interactions.
## Configuration
The object form accepts `RowResizeConfig`:
```ts
import type { RowResizeConfig } from '@revolist/revogrid';
const resizeRow: RowResizeConfig = {
minHeight: 28,
maxHeight: 120,
fullRow: true,
};
grid.resizeRow = resizeRow;
```
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `minHeight` | `number` | `20` | Smallest height a user can assign. |
| `maxHeight` | `number` | No limit | Largest height a user can assign. |
| `fullRow` | `boolean` | `false` | Makes the resize edge available across data rows instead of only row headers. |
Set `grid.resizeRow = false` to disable the interaction at runtime. The plugin remains registered internally, while its resize listeners and handles stay inactive.
## Selected rows
If the grabbed row belongs to the active selected range, RevoGrid applies the same resulting height to every selected row. Grabbing a row outside the range resizes only that row.
## Resize events
RevoGrid emits these events during a resize gesture:
| Event | When it fires |
| --- | --- |
| `beforerowresize` | Before resizing starts. Call `preventDefault()` to cancel the gesture. |
| `rowresize` | While pointer movement applies a live row height. |
| `afterrowresize` | After the completed height is committed. |
| `rowresizecancel` | When an active gesture is cancelled, for example with Escape or a configuration change. |
Each event identifies the row dimension, grabbed row index, affected indexes, current size, previous sizes, and original pointer event.
```js
grid.addEventListener('afterrowresize', event => {
console.log(event.detail.index, event.detail.size);
});
```
## Related guides
- [Row Height](https://rv-grid.com/guide/row/height)
- [Row Headers](https://rv-grid.com/guide/row/headers)
- [Row Selection](https://rv-grid.com/guide/row/selection.pro)
- [Filtering](https://rv-grid.com/guide/filters)
---
# Pin or Freeze Rows in Data Grid
Source: https://rv-grid.com/guide/row/pin
Description: Use Pin or Freeze Rows in Data Grid to keep specific rows always visible at the top or bottom of the grid, even when the user scrolls through the rest of the data.
:::warning
Be aware that pinning columns and rows introduces virtual indexes to the grid. Please read more in the [Viewports section](https://rv-grid.com/guide/viewports).
:::
Pinning (or freezing) rows in a Data Grid is a feature that allows you to keep specific rows always visible at the top or bottom of the grid, even when the user scrolls through the rest of the data. This is particularly useful for displaying headers, totals, or other key information that should remain accessible at all times.
## What are Pinned Rows?
Pinned rows are rows that are fixed in place, separate from the main scrollable data set. You can pin rows to the top or bottom of your grid. These pinned rows are managed through separate data sources, which gives you full control over what is displayed in these fixed positions.
### Key Features:
- **Pinned Top Rows**: These rows are fixed at the top of the grid and remain visible as you scroll through the rest of the data.
- **Pinned Bottom Rows**: These rows are fixed at the bottom of the grid and also remain visible during scrolling.
## How to Implement Pinned Rows
Implementing pinned rows is straightforward. You define separate data sources for the rows you want to pin and then assign these data sources to the `pinnedTopSource` and `pinnedBottomSource` properties of the grid.
### Example
Here’s a simple example of how to pin rows at the top and bottom of your RevoGrid:
```javascript
// Define the data sources for pinned rows
const pinnedTopSource = [{ name: 'Dixon Hudson' }];
const pinnedBottomSource = [{ name: 'Weber Henderson' }];
// Initialize the RevoGrid
const grid = document.querySelector('revo-grid');
// Assign the pinned rows
grid.pinnedTopSource = pinnedTopSource;
grid.pinnedBottomSource = pinnedBottomSource;
```
In this example:
- The `pinnedTopSource` array contains the data for the row that will be pinned at the top of the grid.
- The `pinnedBottomSource` array contains the data for the row that will be pinned at the bottom of the grid.
- These rows will remain fixed in place while the rest of the grid's rows are scrollable.
## Use Cases for Pinned Rows
Pinned rows are useful in a variety of scenarios, including:
- **Headers and Labels**: Pinning headers or labels at the top of the grid to ensure that they are always visible.
- **Totals and Summaries**: Displaying totals, averages, or other summary information in a pinned bottom row to keep key metrics in view.
- **Sticky Notes or Comments**: Keeping important notes or comments accessible by pinning them to the top or bottom of the grid.
## Conclusion
The ability to pin or freeze rows adds a significant layer of functionality to your data grid, enhancing the user experience by keeping critical information always visible. Whether you're displaying headers, summaries, or other key data, pinned rows ensure that your most important content remains front and center.
Try implementing pinned rows in your grid setup today to see how they can improve your grid's usability and functionality.
---
# Row Header in Data Grid
Source: https://rv-grid.com/guide/row/headers
Description: Learn how to customize row headers in Data Grid to display row numbers or use a fully custom template for advanced row header rendering.
[Interface: RowHeaders](https://rv-grid.com/guide/types/Interface.RowHeaders)
Row headers in RevoGrid are versatile and can be used to display row numbers, custom data, or even completely customized templates. This feature enables you to create an Excel-like grid with row numbers or to add meaningful row indicators to your grid.
Row headers are an Excel-like feature that displays row numbers or other custom content on the left side of your grid. This feature is particularly useful for providing context and improving navigation within your data grid. By default, row headers are disabled, but they can be easily enabled and customized to fit your needs.
## Enabling Row Headers
To enable row headers, set the `rowHeaders` property on the data table element. You can use a boolean to show row numbers or pass a custom `RowHeaders` object to define a template.
### Example: Default Row Headers
```typescript
grid.rowHeaders = true; // Enable default row numbers
grid.source = [
{ name: 'Row 1' },
{ name: 'Row 2' },
{ name: 'Row 3' },
];
```
Or you can enable row headers directly in your HTML:
```html
```
In this configuration, the row headers will display default row numbers (e.g., 1, 2, 3).
## Customizing Row Headers
In addition to simply displaying row numbers, RevoGrid allows you to customize row headers by treating them as additional fixed columns on the left side of the grid. This gives you full control over their appearance and behavior, similar to any other column in the grid.
### Customization Options
When customizing row headers, you can use the same properties available for regular columns, such as `size`, `cellTemplate`, and more.
#### Example: Setting Row Header Size
You can set the size of the row headers to accommodate more content or to align with the overall design of your grid:
```js
const grid = document.querySelector('revo-grid');
grid.rowHeaders = {
size: 200 // Set the width of the row header column to 200px
};
```
#### Example: Customizing Row Header Content
You can also use a custom cell template to display content other than just row numbers. This allows you to add icons, text, or even interactive elements to the row headers:
```js
const grid = document.querySelector('revo-grid');
grid.rowHeaders = {
size: 200,
cellTemplate: (h, props) => h('div', `Row ${props.model[props.rowIndex].id}`)
};
```
In this example:
- The `size` property sets the width of the row header column.
- The `cellTemplate` function customizes the content of each row header, displaying "Row" followed by the ID of the row's data.
## Dynamic Row Header Updates
The rowHeaders property can be dynamically updated at runtime. For example:
```typescript
grid.rowHeaders = {
size: 50,
template: (h, { rowIndex }) => `Row ${rowIndex + 1}`,
};
```
## Best Practices for Using Row Headers
- **Use for Navigation**: Row headers make it easier for users to navigate large datasets by providing a constant reference point.
- **Customize for Clarity**: If your grid contains complex data, consider customizing the row headers to display more than just row numbers, such as row identifiers or other relevant information.
- **Balance with Grid Layout**: Ensure that the size and content of row headers do not overwhelm the main content of your grid. Adjust the size and styling to maintain a clean and functional layout.
## When to Use Custom Row Headers
Custom row headers are ideal for:
- Excel-like Numbering: Displaying row numbers to mimic Excel.
- Status Indicators: Showing icons, badges, or status indicators.
- Advanced Customization: Adding dynamic content like row metadata or progress indicators.
## Conclusion
Row headers provide an Excel-like feature that enhances the usability of your data grid by offering a clear reference point on the left side of the table. Whether you need simple row numbers or more customized content, datagrid's row header functionality is flexible and easy to implement.
By enabling and customizing row headers, you can improve the overall user experience, making your data grid more intuitive and easier to navigate. Try incorporating row headers into your grid setup to see how they can benefit your application.
Learn more about the [RowHeaders interface](https://rv-grid.com/guide/types/Interface.RowHeaders).
---
# Row Drag and Drop in Data Grid
Source: https://rv-grid.com/guide/row/order
Description: Use Row Drag and Drop in Data Grid to reorder rows dynamically through a drag-and-drop interface.
The Data Grid **Row Drag and Drop** feature created to rearrange rows dynamically through a drag-and-drop interface. This functionality enhances the interactivity of your grid by allowing users to reorder rows easily, improving data organization and management.
## Key Features
- **Drag-and-Drop Reordering**:
- **Purpose**: Enables users to reorder rows by dragging a designated reordering cell.
- **Benefit**: Provides an intuitive and interactive way to rearrange row positions within the grid.
- **Special Reordering Cell**:
- **Purpose**: Utilizes a specific cell to facilitate the dragging and dropping of rows.
- **Benefit**: Simplifies the reordering process by clearly indicating the draggable area.
- **Configuration**:
- **Default State**: Row reordering is disabled by default to maintain initial grid configurations.
- **Enable Reordering**: To activate row reordering, configure the `rowDrag` property in the column settings.
## Example Usage
To enable row reordering in your grid, set the `rowDrag` property in the column configuration:
```tsx
const grid = document.querySelector('revo-grid');
// Configure column property to enable row reordering
grid.columns = [
{ title: 'Name', field: 'name', rowDrag: true }, // Enables row reordering
{ title: 'Age', field: 'age' },
];
```
## Explanation
- **`rowDrag` Property**: Set to `true` in the column configuration where the reordering cell is specified. This activates the drag-and-drop functionality for rows.
## Benefits
- **Enhanced Interactivity**: Allows users to rearrange rows according to their preferences, making data management more flexible.
- **Improved Usability**: Offers an intuitive way for users to organize data without needing complex controls or additional tools.
## Implementation Tips
- Ensure that the `rowDrag` property is set appropriately in your column configuration to enable the feature.
- Customize the appearance and behavior of the reordering cell to match your grid’s design and user experience goals.
## Limitations & Pro Version
- **Basic Functionality**: The standard row ordering feature provides fundamental drag-and-drop capabilities.
- **Advanced Features**: For more advanced row ordering options, such as custom drag handles, advanced visual cues, or additional configuration settings, consider using the [Pro version](https://rv-grid.com/guide/row/order.pro) of RevoGrid.
---
# Row Grouping in Data Grid
Source: https://rv-grid.com/guide/row/grouping
Description: Learn how to configure row grouping in RevoGrid using TypeScript. Easily group rows based on specific properties for better data organization and visualization.
## Grouping Configuration
The grouping option takes an object with the props property, which specifies the columns to group by. In the example above, rows are grouped by the projectName property.
```typescript
import { defineCustomElements } from '@revolist/revogrid/loader'
import { type DataType } from '@revolist/revogrid'
defineCustomElements()
// Create grid element
const grid = document.createElement('revo-grid')
document.body.appendChild(grid)
// Define columns
const columns = [
{
name: '🎰',
prop: 'a',
},
]
grid.columns = columns
grid.source = ((rowsNumber) => {
const result: DataType[] = []
const all = rowsNumber
for (let j = 0; j < all; j++) {
let row = j
if (!result[row]) {
result[row] = {
id: row,
projectName: j % 2 ? 'yes' : 'no',
}
}
result[row]['a'] = `I am row ${row}`
}
return result
})(100)
grid.grouping = { props: ['projectName'] }
```
## Vue 3 - Row Grouping
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue.row-grouping.vue)
::: code-group
<<< @/demo/vue/vue.row-grouping.vue
:::
### Example Grouping Output
With the provided configuration:
- Rows with projectName: 'yes' are grouped together.
- Rows with projectName: 'no' are grouped separately.
## Dynamic Updates
Grouping can be updated dynamically by modifying the grouping property of the grid. For example:
```typescript
grid.grouping = { props: ['newGroupingProperty'] };
```
For more details, check the [GroupingOptions interface](https://rv-grid.com/guide/types/TypeAlias.GroupingOptions).
## Related guides
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Understanding Viewports](https://rv-grid.com/guide/viewports)
## Pro features
### [Row Grouping Drag and Drop](https://rv-grid.com/pro/)
Let users drag columns into a grouping panel to create grouped rows interactively. This is useful when users need to change grouping dimensions while exploring operational or reporting data.
### [Grouping Aggregation](https://rv-grid.com/pro/)
Add summary values such as sum, average, count, and other calculations to grouped rows. Use it when row groups need totals or rollups instead of only visual separation.
### [Pivot Table](https://rv-grid.com/pro/)
Extend row grouping into multidimensional analysis with row dimensions, column dimensions, values, subtotals, grand totals, and drill-down state. This is the next step when grouping becomes an analytics workflow.
### [Hierarchical Data View](https://rv-grid.com/pro/)
Represent parent-child row structures with expand and collapse behavior, hierarchy-aware visibility, and row integration. Use it when the row relationship is a tree rather than a flat group.
### [Row Advanced Drag and Drop](https://rv-grid.com/pro/)
Enable advanced row movement with custom drag handles, drop behavior, and multi-item workflows. This helps when grouped or structured rows also need controlled reordering.
### [Row Checkbox Selection](https://rv-grid.com/pro/)
Add checkbox-based row selection with keyboard interactions and bulk selection behavior. This is useful when users need to act on full groups or selected rows inside grouped datasets.
---
# Accessibility in Data Grids
Source: https://rv-grid.com/guide/wcag
# Accessibility in Data Grids
RevoGrid is committed to making data grids accessible to everyone, following international accessibility standards and best practices for Data Tables.
This includes implementing keyboard navigation, support for screen readers, and ensuring that all interactive elements are easy to use for people with disabilities.
## Accessibility Guidelines
Our Data Grid adheres to globally accepted accessibility standards such as WCAG (Web Content Accessibility Guidelines) and other regional regulations like ADA (Americans with Disabilities Act) and Section 508 in the US, as well as the European Accessibility Act (EAA). The aim is to support WCAG 2.1 Level AA, which is the most common target for organizations seeking to ensure their web applications are accessible.
### Key Guidelines Followed:
- **WCAG (Web Content Accessibility Guidelines)**: Provides a comprehensive set of criteria for making web content accessible to a wide range of users, including those with disabilities.
- **WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications)**: Offers best practices for making web applications like RevoGrid accessible, particularly when it comes to complex interactive components like data grids.
## Keyboard Navigation
Comprehensive keyboard navigation ensures that all users, including those who rely on keyboards instead of a mouse, can interact with the grid seamlessly.
### Key Navigation Features:
- **Tab Sequence Management**: Following WAI-ARIA practices, grid ensures that only the relevant focusable elements are included in the tab sequence, making navigation intuitive.
- **Arrow Keys**: Navigate between cell elements using the arrow keys, ensuring that users can move horizontally and vertically across the grid.
- **Ctrl/CMD + A Keys**: Quickly all cells of the entire grid.
- **Enter/Escape**: Select a cell or row for editing, or exit the edit mode using `Enter` or `Escape`.
- **Ctrl/CMD + C/V Keys**: Copy and paste cells.
## Customizing Accessibility Features
Grid events allow developers to customize and enhance the accessibility features to better suit their application’s needs. This can be done by intercepting the events and modifying the behavior as needed.
- [Auto-Focus on Next Line](https://rv-grid.com/guide/wcag.next-focus.pro): This feature automatically moves the focus to the next row when the user reaches the last cell of the current row, making it easier for users to navigate through the grid.
## Density and Accessibility
Themes are also provide options to adjust the density of rows and columns, making it easier to read and interact with the grid for users with different needs.
### Setting Density
You can set the density of the grid using the `row-size` prop. This can be controlled programmatically or through the UI, providing flexibility based on user preferences.
- **Standard Density 27px**: The default setting, offering standard Excel view.
- **Compact Theme Density 32px**: Reduces the space between rows and columns for users who need to view more data at once.
- **Material Theme Density 42px**: Increases spacing for easier reading, useful for users with visual impairments.
---
# RTL (Right-to-Left) Support
Source: https://rv-grid.com/guide/rtl
RevoGrid provides comprehensive support for Right-to-Left (RTL) languages and layouts, making it suitable for applications targeting Arabic, Hebrew, Persian, and other RTL language users. The RTL support is implemented through a dedicated plugin that automatically handles column ordering, text alignment, and layout adjustments.
## Overview
RTL support in RevoGrid includes:
- **Automatic column reordering**: Columns are automatically reversed when RTL mode is enabled
- **Text alignment**: Cell content is properly aligned for RTL languages
- **Layout adjustments**: Scrollbars, headers, and interactive elements are positioned correctly
- **Plugin-based architecture**: RTL functionality is implemented as a plugin for easy integration
## Basic Usage
### Enabling RTL Mode
To enable RTL support, simply set the `rtl` property to `true` on your RevoGrid component:
```html
```
### JavaScript Example
```typescript
// Basic RTL setup
const grid = document.querySelector('revo-grid');
grid.rtl = true;
// Configure columns and data
grid.columns = [
{ prop: 'name', name: 'الاسم' },
{ prop: 'age', name: 'العمر' },
{ prop: 'city', name: 'المدينة' }
];
grid.source = [
{ name: 'أحمد', age: 25, city: 'القاهرة' },
{ name: 'فاطمة', age: 30, city: 'الإسكندرية' },
{ name: 'محمد', age: 28, city: 'الجيزة' }
];
```
### Framework Examples
#### Vue 3
```vue
```
#### React
```tsx
import { useState } from 'react';
function RTLGrid() {
const [isRTLEnabled, setIsRTLEnabled] = useState(true);
return (
);
}
```
## Advanced Configuration
### Dynamic RTL Toggle
You can dynamically toggle RTL mode based on user preferences or application state:
```typescript
// Toggle RTL mode
function toggleRTL() {
const grid = document.querySelector('revo-grid');
grid.rtl = !grid.rtl;
}
// Listen for RTL state changes
grid.addEventListener('rtlstatechanged', (event) => {
console.log('RTL state changed:', event.detail.rtl);
});
```
## Styling Considerations
### Custom RTL Styles
RevoGrid automatically applies RTL-specific styles when the `rtl` attribute is present. You can also add custom RTL styles:
```css
/* Custom RTL styles */
revo-grid[rtl] {
/* Custom RTL-specific styles */
font-family: 'Arial', sans-serif;
}
revo-grid[rtl] .rgCell {
/* Custom cell styles for RTL */
text-align: right;
direction: rtl;
}
```
### RTL with Custom Cell Renderers
When using custom cell renderers, ensure they respect RTL layout:
```typescript
const columns = [
{
prop: 'name',
name: 'الاسم',
cellTemplate: (h, props) => {
return h('div', {
style: {
textAlign: props.model.rtl ? 'right' : 'left',
direction: props.model.rtl ? 'rtl' : 'ltr'
}
}, props.model[props.prop]);
}
}
];
```
## Best Practices
### 1. Consistent RTL Implementation
- Always test your application in both LTR and RTL modes
- Ensure all text content is properly translated for RTL languages
- Consider cultural differences in data presentation
### 2. Performance Considerations
- RTL transformation is handled efficiently by the plugin system
- Column reordering is performed only when necessary
- No performance impact when RTL is disabled
### 3. Accessibility
- Ensure proper ARIA attributes for RTL content
- Test with screen readers that support RTL languages
- Consider keyboard navigation patterns for RTL users
### 4. Data Formatting
- Use appropriate number and date formatting for RTL locales
- Consider currency symbol positioning for RTL languages
- Ensure proper text direction for mixed content
## Troubleshooting
### Common Issues
1. **Columns not reordering**: Ensure the RTL plugin is properly loaded
2. **Text alignment issues**: Check if custom CSS is overriding RTL styles
3. **Performance problems**: Verify that RTL mode is only enabled when needed
### Debug Mode
Enable debug mode to troubleshoot RTL issues:
```typescript
// Enable debug mode
const grid = document.querySelector('revo-grid');
grid.debug = true;
// Check RTL state
console.log('RTL enabled:', grid.rtl);
```
### Events
The RTL plugin emits events when the RTL state changes:
```typescript
// Listen for RTL state changes
grid.addEventListener('rtlstatechanged', (event) => {
const { rtl } = event.detail;
console.log('RTL state changed to:', rtl);
});
```
This comprehensive RTL support ensures that RevoGrid works seamlessly with RTL languages and provides a native experience for users in RTL locales.
---
# RevoGrid Editing
Source: https://rv-grid.com/guide/editing
Description: Configure inline editing in RevoGrid, control read-only behavior, open editors programmatically, and handle edit lifecycle events safely.
RevoGrid supports spreadsheet-style editing out of the box. You can make the whole grid editable, lock specific columns, register custom editors, and intercept writes before they are committed.
## How editing works
Editing in RevoGrid is controlled by a few core pieces:
- `readonly` can lock the whole grid or specific columns
- `editors` registers custom editor implementations
- `applyOnClose` controls whether closing an editor saves the current value
- lifecycle events such as `beforeedit`, `beforeeditstart`, and `afteredit` let you validate or sync changes
For source-owned synchronization without edit event handlers, see [Proxy Source Editing](https://rv-grid.com/guide/proxy-source). That pattern passes proxied row models to `source` so RevoGrid writes route through your application store.
## Minimal editable setup
```javascript
const grid = document.querySelector('revo-grid');
grid.columns = [
{ prop: 'id', name: 'ID', readonly: true },
{ prop: 'name', name: 'Name' },
{ prop: 'price', name: 'Price' },
];
grid.source = [
{ id: 1, name: 'Apple', price: 1.2 },
{ id: 2, name: 'Banana', price: 0.5 },
];
```
By default, columns without `readonly: true` can be edited.
If the grid itself has `readonly = true`, that top-level flag wins and editing is disabled across all columns.
## Read-only modes
### Lock the whole grid
```javascript
const grid = document.querySelector('revo-grid');
grid.readonly = true;
```
### Lock individual columns
```javascript
grid.columns = [
{ prop: 'id', name: 'ID', readonly: true },
{ prop: 'name', name: 'Name' },
{ prop: 'price', name: 'Price', readonly: true },
];
```
### Dynamic read-only rules
`readonly` can also be a function in a column type, which is useful when editability depends on row data.
Example:
```ts
grid.columnTypes = {
editableWhenDraft: {
readonly({ model }) {
return model.status !== 'draft';
},
},
};
```
## Save control with `applyOnClose`
Set `applyOnClose` when you want editor closing to commit the current value except for `Escape`-style cancellations:
```ts
grid.applyOnClose = true;
```
This is useful when building custom editors with blur or close interactions.
Typical use case:
- click into a cell
- change the value
- click outside the editor
- save automatically unless the user explicitly canceled
## Programmatically open an editor
Use `setCellEdit` when your UI needs to move users directly into edit mode:
```ts
await grid.setCellEdit(0, 'price');
```
Arguments:
- first argument: row index in the selected row viewport
- second argument: column `prop`
- optional third argument: row source type such as `rgRow`, `rowPinStart`, or `rowPinEnd`
Read more in [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control).
## Editing lifecycle events
These are the most important hooks for application logic:
- `beforeeditstart`: runs before the editor opens
- `beforeedit`: runs before data is committed; can cancel or rewrite the value
- `beforerangeedit`: same idea for range updates
- `afteredit`: runs after the edit or range change has been applied
Example:
```javascript
grid.addEventListener('beforeedit', event => {
const { model, prop, val } = event.detail;
if (prop === 'price' && Number(val) < 0) {
event.preventDefault();
return;
}
if (prop === 'name') {
event.detail.val = String(val).trim();
}
});
grid.addEventListener('afteredit', event => {
console.log('Edit applied', event.detail);
});
```
If you need to normalize values, `beforeedit` is the safest place to do it.
Example:
```ts
grid.addEventListener('beforeedit', event => {
if (event.detail.prop === 'email') {
event.detail.val = String(event.detail.val).toLowerCase();
}
});
```
## Editing and focus
Editing and focus are closely connected in RevoGrid:
- `canFocus` controls whether focus is rendered
- `setCellsFocus` can move focus before opening an editor
- `clearFocus` removes the active focus state
- `getSelectedRange` helps when edits depend on the current selection
If you are building custom keyboard or toolbar workflows, combine the public methods instead of trying to target internal DOM elements directly.
Example toolbar flow:
```ts
await grid.setCellsFocus({ x: 1, y: 2 }, { x: 1, y: 2 });
await grid.setCellEdit(2, 'name');
```
## Common editing scenarios
### Prevent invalid numbers
```ts
grid.addEventListener('beforeedit', event => {
if (event.detail.prop === 'price' && Number(event.detail.val) < 0) {
event.preventDefault();
}
});
```
### Save on confirmed change
```ts
grid.addEventListener('afteredit', async event => {
await saveRow(event.detail.model);
});
```
## Related guides
- [Cell Editor](https://rv-grid.com/guide/cell/editor)
- [Proxy Source Editing](https://rv-grid.com/guide/proxy-source)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
## Related Pro features
If you need richer editing workflows, RevoGrid Pro adds editors and validation patterns such as row editors, checkbox editors, timeline editors, dropdown editors, and validation helpers. Start from [RevoGrid Pro](https://rv-grid.com/pro/).
---
# Data Grid Export
Source: https://rv-grid.com/guide/export.plugin
Description: Export data from RevoGrid to CSV in the core package, use RevoGrid Pro for richer Excel export workflows, or add the PDF export package for browser-side PDF output.
# Export Data from your Data Grid to file
With our data grid you can export your data to file.
There are three common ways to export data:
- [Export to CSV file](#Export-to-CSV-file)
- [Export to Excel file with RevoGrid Pro](https://rv-grid.com/guide/data-grid-export-excel)
- [Export to PDF file](https://rv-grid.com/guide/pdf-export)
## Export to CSV file
To export data to CSV file you need to use `exporting` option.
- Setup `exporting` option on `revo-grid` to `true`:
``` tsx
```
- Access export plugin from plugin list:
``` js
const grid = document.querySelector('revo-grid');
grid.getPlugins().then(plugins => {
plugins.forEach(p => {
if (p.exportFile) {
const exportPlugin = p;
exportPlugin.exportFile({ filename: 'new file' });
}
})
});
```
## Public methods
There are next methods available in export plugin and `options` object as `FormatterOptions`:
- `exportFile(options)` - download file;
- `exportBlob(options)` - export Blob object;
- `exportString(options)` - get data string.
## Options
General options are available for export:
```ts
type FormatterOptions = {
mime: string; // text/csv
encoding: string;
fileKind: string; // csv
bom: boolean;
columnDelimiter: string; // ','
rowDelimiter: string; // '\r\n'
filename?: string;
}
```
:::tip
For the latest information it's recommended to read [export-plugin](https://github.com/revolist/revogrid/blob/master/src/plugins/export/export.plugin.ts) file for better understanding of parameters and options.
:::
## Related Pro features
Need richer spreadsheet export workflows? [RevoGrid Pro Excel export](https://rv-grid.com/guide/data-grid-export-excel) creates workbook files that can preserve the visible grid layout, including column order, hidden columns, frozen panes, styles, merged cells, and formulas. Start with [RevoGrid Pro](https://rv-grid.com/pro/) or compare plans on [Feature Comparison](https://rv-grid.com/pro/feature-table).
## Related PDF export package
Need a lightweight browser-side PDF export button? Use [`@revolist/revogrid-pdf-export`](https://www.npmjs.com/package/@revolist/revogrid-pdf-export), a RevoGrid plugin powered by [pdfmake](https://pdfmake.github.io/docs/). It exports visible rows and columns into a simple PDF table and supports grouped column headers. See [PDF Export](https://rv-grid.com/guide/pdf-export).
---
# RevoGrid PDF Export
Source: https://rv-grid.com/guide/pdf-export
Description: Export visible RevoGrid rows and columns to PDF with the lightweight @revolist/revogrid-pdf-export plugin powered by pdfmake.
Export [RevoGrid](https://rv-grid.com/) data to clean, shareable PDF files with a small browser-side plugin powered by [pdfmake](https://pdfmake.github.io/docs/).
[`@revolist/revogrid-pdf-export`](https://www.npmjs.com/package/@revolist/revogrid-pdf-export) is a lightweight add-on package for teams that need a practical PDF export button without building a full reporting pipeline. It reads visible RevoGrid data, preserves column headers, respects trimmed or filtered rows, and creates a simple [pdfmake document definition](https://pdfmake.github.io/docs/0.1/document-definition-object/) that can be downloaded, previewed, uploaded, or customized.
::: tip Add-on package
PDF export is delivered as a separate package. Core RevoGrid includes CSV export through the built-in export plugin. Excel-focused export workflows are available in RevoGrid Pro.
:::
## Why use it
- Lightweight client-side PDF export for RevoGrid.
- Works through the standard [RevoGrid plugin API](https://rv-grid.com/guide/plugin/).
- Exports visible rows and visible columns.
- Supports grouped column headers.
- Lets you download a PDF, return a browser [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob), or access the pdfmake document definition.
- Provides a cancelable `beforepdfexport` hook for customization.
- Keeps the first version focused: fast to adopt, easy to reason about, and simple to extend.
## Install
```sh
npm install @revolist/revogrid-pdf-export
```
The package expects RevoGrid to be present in your app. Install RevoGrid separately if your project does not already use it:
```sh
npm install @revolist/revogrid
```
## Quick start
Register `ExportPdfPlugin` in the grid plugin list, then retrieve the plugin instance with `getPlugins()`.
```ts
import { ExportPdfPlugin } from '@revolist/revogrid-pdf-export';
const grid = document.querySelector('revo-grid');
if (grid) {
grid.plugins = [ExportPdfPlugin];
const plugins = await grid.getPlugins();
const pdf = plugins.find(plugin => plugin instanceof ExportPdfPlugin);
await pdf?.exportPdf({
filename: 'orders.pdf',
title: 'Orders',
});
}
```
## API
### `exportPdf(options?)`
Creates and downloads a PDF file.
```ts
await pdf.exportPdf({
filename: 'orders.pdf',
title: 'Orders Report',
});
```
### `exportBlob(options?)`
Creates a PDF and returns it as a browser `Blob`. Use this when you want to upload, preview, store, or handle the file yourself.
```ts
const blob = await pdf.exportBlob({
title: 'Orders Report',
});
```
### `getDocumentDefinition(options?)`
Returns the [pdfmake document definition](https://pdfmake.github.io/docs/0.1/document-definition-object/) before a PDF is created. Use this when you want full control over the final pdfmake rendering step.
```ts
const definition = await pdf.getDocumentDefinition({
pageOrientation: 'portrait',
});
```
## Options
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `filename` | `string` | `revogrid-export.pdf` | Download filename. `.pdf` is added automatically when omitted. |
| `title` | `string` | `RevoGrid Export` | Title shown above the exported table. |
| `pageOrientation` | `'portrait' \| 'landscape'` | `landscape` | PDF page orientation. |
| `includeColumnHeaders` | `boolean` | `true` | Includes the column header row. |
| `includeGroupHeaders` | `boolean` | `true` | Includes grouped column header rows when present. |
| `maxRows` | `number` | unlimited | Limits exported data rows. |
| `tableLayout` | `string` | `lightHorizontalLines` | [pdfmake table layout](https://pdfmake.github.io/docs/0.1/document-definition-object/tables/) name. |
## Customize the PDF
The plugin emits a cancelable `beforepdfexport` event with `{ data, documentDefinition, options }`.
Use it to adjust the pdfmake document definition, add metadata, change styles, add headers or footers, or stop the export.
```ts
grid.addEventListener('beforepdfexport', event => {
event.detail.documentDefinition.info = {
title: 'Orders Report',
subject: 'Monthly order export',
};
event.detail.documentDefinition.footer = currentPage => ({
text: `Page ${currentPage}`,
alignment: 'center',
fontSize: 8,
});
});
```
Call `event.preventDefault()` to cancel the export.
## What gets exported
The plugin focuses on data, not pixel-perfect rendering. It exports:
- visible row data
- visible columns
- column names
- grouped column headers
- filtered or trimmed grid state through RevoGrid's visible source APIs
It does not attempt to reproduce custom cell renderers, DOM styling, images, row headers, pinned layout visuals, or editor UI. This keeps the PDF output small and predictable.
## Framework usage
The plugin is framework-agnostic. Use it anywhere you can pass RevoGrid plugins:
- [Vanilla JavaScript / TypeScript](https://rv-grid.com/guide/ts/)
- [React](https://rv-grid.com/guide/react/)
- [Vue 3](https://rv-grid.com/guide/vue3/)
- [Angular](https://rv-grid.com/guide/angular/)
- [Svelte](https://rv-grid.com/guide/svelte/)
## When to use each export option
| Requirement | Recommended option |
| --- | --- |
| Simple CSV data export | [Core CSV export](https://rv-grid.com/guide/export.plugin) |
| Browser-side PDF table export | `@revolist/revogrid-pdf-export` |
| Excel workbook export/import | [RevoGrid Pro Excel export](https://rv-grid.com/guide/data-grid-export-excel) |
| Fully custom report layout | Use `getDocumentDefinition()` and customize pdfmake output |
## Links
- [npm package](https://www.npmjs.com/package/@revolist/revogrid-pdf-export)
- [GitHub repository](https://github.com/revolist/revogrid-pdf-export)
- [pdfmake documentation](https://pdfmake.github.io/docs/)
- [RevoGrid plugin guide](https://rv-grid.com/guide/plugin/)
- [Core CSV export](https://rv-grid.com/guide/export.plugin)
- [RevoGrid Pro Excel export](https://rv-grid.com/guide/data-grid-export-excel)
---
# Export Excel
Source: https://rv-grid.com/guide/data-grid-export-excel
Description: Export RevoGrid Pro data to Excel workbooks with visible grid layout, styles, frozen panes, merged cells, formulas, and workbook options.
Export production grid views to Excel with [RevoGrid Pro](https://rv-grid.com/pro/). The Pro Excel export is built for teams that need more than a raw data dump: it creates workbook files that keep the structure and feel of the grid your users already work with.
Use Excel export when a report needs to leave the browser and still feel like the original table - column order, visible columns, frozen panes, styling, merged cells, and formulas can travel with the exported workbook.
::: tip Pro feature
Excel export and import are part of [RevoGrid Pro](https://rv-grid.com/pro/). Core RevoGrid includes [CSV export](https://rv-grid.com/guide/export.plugin), and browser-side PDF export is available through the [`@revolist/revogrid-pdf-export`](https://rv-grid.com/guide/pdf-export) add-on.
:::
## Why Use Pro Excel Export
- Export `.xlsx` workbooks directly from the grid experience.
- Preserve the visible grid layout so exported files match what users see.
- Keep column order and hidden column state in the workbook output.
- Carry pinned or frozen layout into Excel frozen panes.
- Export styled cells for report-ready workbooks.
- Support merged cells and spanned report layouts.
- Keep formula-driven data useful outside the application.
- Use workbook options for file name, sheet name, compression, and format.
- Pair export with Pro import workflows for spreadsheet round trips.
## What Gets Preserved
RevoGrid Pro Excel export is designed around the rendered grid state, not only the original source array.
| Grid capability | Excel export behavior |
| --- | --- |
| Column order | Exports columns in the current visible order. |
| Column visibility | Hidden columns stay out of the exported view. |
| Frozen columns and rows | Maps pinned grid regions to Excel-style frozen panes where supported. |
| Cell styles | Preserves table styling and formatting for a closer visual match. |
| Grouped headers | Keeps structured header layout useful in the workbook. |
| Merged cells | Exports merged and spanned regions from Pro merge workflows. |
| Formulas | Works with the Pro formula pipeline so calculated sheets remain useful after export. |
For the related grid features, see [Column Pinning](https://rv-grid.com/guide/column/pin), [Row Pinning](https://rv-grid.com/guide/row/pin), [Cell Merge](https://rv-grid.com/guide/cell/merge), and [Excel Formulas](https://rv-grid.com/guide/cell/formula).
## Quick Example
The exact plugin registration depends on your Pro package setup, but the export flow is intentionally small: enable the Pro Excel export plugin, then send an export configuration with workbook and sheet options.
```ts
const exportConfig: ExportExcelEvent = {
sheetName: 'Property Data',
workbookName: 'Properties.xlsx',
writingOptions: {
type: 'file',
bookType: 'xlsx',
compression: true,
},
};
```
Use your Pro setup to pass this configuration to `ExportExcelPlugin`. The plugin handles workbook creation from the current grid state.
## Workbook Formats
The Pro Excel export workflow targets common spreadsheet formats used by Excel-compatible tools. The Pro feature catalog includes `xlsx`, `xlsm`, `xlsb`, `xls`, and related workbook formats.
| Option | Use case |
| --- | --- |
| `xlsx` | Default modern Excel workbook format. |
| `xlsm` | Macro-enabled workbook workflows. |
| `xlsb` | Binary workbook workflows where supported. |
| `xls` | Legacy Excel compatibility. |
Implementation dependencies are versioned with RevoGrid Pro. See the [RevoGrid Pro third-party policy](https://rv-grid.com/pro/policies/3rdparty) for writer package and licensing notes.
## Writing Options
`writingOptions` controls how the workbook is generated. Individual writer options can vary by Pro version, so use the TypeScript types shipped with your installed Pro package as the final source of truth.
| Option | Description |
| --- | --- |
| `type` | Output mode used by the workbook writer. |
| `bookType` | Workbook format such as `xlsx`, `xlsm`, `xlsb`, or `xls`. |
| `compression` | Enables compression for supported workbook formats. |
| `ignoreEC` | Suppresses compatible spreadsheet warnings such as number-stored-as-text checks when supported. |
```ts
const exportConfig: ExportExcelEvent = {
sheetName: 'Q4 Revenue',
workbookName: 'q4-revenue.xlsx',
writingOptions: {
type: 'file',
bookType: 'xlsx',
compression: true,
ignoreEC: true,
},
};
```
## Best Use Cases
Excel export is strongest when users expect the exported file to become a working spreadsheet, not just an archive.
- Financial models with formulas and pinned summary regions.
- Operations dashboards where teams sort, filter, and share workbook snapshots.
- Reporting tables with merged headers, grouped columns, and styled totals.
- Compliance workflows that need offline Excel files for review.
- Internal tools where users already rely on Excel for analysis and handoff.
## Choosing An Export Path
| Requirement | Recommended option |
| --- | --- |
| Raw data download | [Core CSV export](https://rv-grid.com/guide/export.plugin) |
| Excel workbook with layout, styles, formulas, merge, and freeze support | [RevoGrid Pro Excel export](https://rv-grid.com/pro/) |
| Shareable table PDF from the browser | [PDF export add-on](https://rv-grid.com/guide/pdf-export) |
| Advanced spreadsheet-like editing before export | [RevoGrid Pro spreadsheet features](https://rv-grid.com/pro/) |
## Related Pro Features
- [RevoGrid Pro](https://rv-grid.com/pro/)
- [Pro feature comparison](https://rv-grid.com/pro/feature-table)
- [Excel Formulas](https://rv-grid.com/guide/cell/formula)
- [Cell Merge](https://rv-grid.com/guide/cell/merge)
- [Column Pinning](https://rv-grid.com/guide/column/pin)
- [Row Pinning](https://rv-grid.com/guide/row/pin)
- [Pro third-party tools and libraries](https://rv-grid.com/pro/policies/3rdparty)
---
# RevoGrid Filtering
Source: https://rv-grid.com/guide/filters
Description: Enable built-in filtering in RevoGrid, configure per-column filter types, preserve filter state, customize filter logic, and upgrade to RevoGrid Pro advanced filtering.
Filtering lets users narrow the visible rows without changing the original `source`. RevoGrid keeps the full dataset available and hides non-matching physical row indexes through the trimming pipeline, so filtering works together with virtual scrolling, sorting, editing, and `getVisibleSource()`.
## Performance by design
RevoGrid filters the data model, not the rendered DOM. It keeps the original `source` intact, calculates which rows should be visible, and lets row virtualization render only the small portion currently in the viewport. This makes filtering suitable for large, interactive datasets without creating a DOM element for every matching row.
Large local filter operations automatically run in short batches so the browser can stay responsive between slices of work. When an active filter is reapplied after replacing `source`, RevoGrid keeps the new rows hidden until the result is ready, then publishes the filtered view once. Users see an empty pending view followed by the correct result—not a flash of the complete unfiltered dataset.
- Small datasets keep the immediate synchronous path.
- Large datasets use a responsive, cancellable path, so a newer filter or source can replace stale work.
- Filtering composes with sorting, grouping, tree visibility, and other row trims before rows become visible.
Client-side filtering still evaluates the local records and any active conditions. Keep custom filter functions lightweight; for datasets that should not live entirely in the browser, use [server-side filtering](https://rv-grid.com/guide/server-side-data#remote-filtering). See [Performance and Virtualization](https://rv-grid.com/guide/performance) for broader large-data guidance.
## Enable filtering
Turn on the built-in filter plugin with the grid-level `filter` prop:
```ts
const grid = document.querySelector('revo-grid');
grid.source = [
{ name: 'Steve', role: 'Admin', score: 92 },
{ name: 'Anna', role: 'Editor', score: 76 },
{ name: 'John', role: 'Viewer', score: 61 },
];
grid.columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'role', name: 'Role' },
{ prop: 'score', name: 'Score', filter: 'number' },
];
grid.filter = true;
```
The grid-level `filter` value enables the plugin. The column-level `filter` value decides whether a column has a filter button and which filter family the panel should use.
[RevoGrid filter prop](https://rv-grid.com/guide/types/JSX.Interface.RevoGrid#properties)
[Column filter option](https://rv-grid.com/guide/types/Interface.ColumnRegular#properties)
## Column filter options
Use `filter` on a column when you need to override the default behavior.
```ts
const columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'internalId', name: 'Internal ID', filter: false },
{ prop: 'score', name: 'Score', filter: 'number' },
{ prop: 'status', name: 'Status', filter: ['string', 'selection'] },
{
prop: 'reference',
name: 'Reference',
filter: { type: 'string', default: 'eq' },
},
{
prop: 'notes',
name: 'Notes',
filter: { type: 'string', default: false },
},
];
```
| Value | Use it for |
| --- | --- |
| `true` | Enable the default filter family for the column. |
| `false` | Hide the filter UI for the column. |
| `'string'` | Text matching such as contains, starts with, and equals. |
| `'number'` | Numeric comparisons such as greater than and less than. |
| `string[]` | Multiple filter families, often used by Pro or custom filters. |
| `{ type, default }` | Select one or more filter families and optionally override the initial operator, or set `default: false` to open this column's panel empty. |
## Default filter conditions
When a column has no saved or active conditions, opening its filter panel shows
one removable draft condition. String columns start with **Contains** and number
columns start with **=**. Boolean, array, and custom filter families use their
first available operator.
The draft is ready for input but is not an applied filter. Opening or closing
the panel does not filter rows, activate the header filter icon, emit filtering
events, or add the draft to persisted filter state. Entering a value or
explicitly selecting an operator promotes it to a normal condition. If dynamic
filtering is disabled, the promoted condition remains local until **Save**.
Use the structured column form to choose a different initial operator:
```ts
grid.columns = [
{
prop: 'name',
name: 'Name',
filter: { type: 'string', default: 'eq' },
},
{
prop: 'score',
name: 'Score',
filter: { type: ['number', 'string'], default: 'gte' },
},
];
```
To keep the original empty-panel behavior everywhere, disable default drafts in
the grid filter configuration. A column can opt out independently with
`default: false`. Conversely, an explicit operator on a column opts that column
back in when the grid-wide setting is disabled.
```ts
grid.filter = { defaultFilter: false };
grid.columns = [
{ prop: 'name', filter: 'string' }, // Opens empty.
{ prop: 'notes', filter: { type: 'string', default: false } }, // Opens empty.
{ prop: 'status', filter: { type: 'string', default: 'eq' } }, // Opens with Equal.
];
```
The override must name an operator available to one of the configured families.
It is resolved after `include` and custom filters are applied. If it is invalid
or excluded, RevoGrid uses the built-in family default when available, then the
first available operator from the first configured family.
Removing the draft or clicking **Reset** leaves the current panel empty. A new
draft is created the next time that column's panel is opened. Existing filters
loaded through `collection`, `multiFilterItems`, or the `filter` event are shown
as-is and never receive an extra draft.
## Built-in filter operations
String columns support `notEmpty`, `empty`, `eq`, `notEq`, `begins`, `contains`, and `notContains`.
Number columns support `notEmpty`, `empty`, `eqN`, `neqN`, `gt`, `gte`, `lt`, and `lte`.
Boolean and array columns support the blank operations `notEmpty` and `empty`.
In the filter panel, `empty` is labeled **Is blank** and `notEmpty` is labeled **Is not blank**. The operation ids have not changed, so existing saved filter state remains compatible. These ids are also the values used by `include`, localization, and event payloads.
[FilterItem](https://rv-grid.com/guide/types/Interface.FilterItem)
[FilterType](https://rv-grid.com/guide/types/TypeAlias.FilterType)
## Configure `ColumnFilterConfig`
Pass an object to `grid.filter` when you need controlled behavior instead of the default plugin setup.
```ts
grid.filter = {
defaultFilter: false,
include: ['contains', 'eq', 'notEmpty', 'gt', 'gte', 'lt', 'lte'],
disableDynamicFiltering: true,
closeFilterPanelOnOutsideClick: false,
allowDuplicateOperators: false,
};
```
Important options:
| Option | Purpose |
| --- | --- |
| `blankSemantics` | Defines which source values the blank operators match across the grid. |
| `defaultFilter` | Controls whether empty panels start with a draft condition. Defaults to `true`. |
| `collection` | Restores single-filter state by column prop. |
| `multiFilterItems` | Restores multiple filters per column, including `and` / `or` relations. |
| `include` | Limits the operations shown in the dropdown. |
| `customFilters` | Registers custom operations. |
| `filterProp` | Uses a custom column property instead of `filter` to decide whether a column is filterable. |
| `localization` | Replaces filter captions and operation names. |
| `disableDynamicFiltering` | Applies changes only when the user confirms. |
| `closeFilterPanelOnOutsideClick` | Controls whether outside clicks close the filter panel. |
| `allowDuplicateOperators` | Allows the same operator to be selected more than once per column. Defaults to `true`; set to `false` to make visible operators mutually exclusive in the panel. |
When `allowDuplicateOperators` is `false`, the filter panel hides operators
already used by the current column from the **Add condition** dropdown. Existing
conditions remain editable, and programmatically supplied duplicate
`multiFilterItems` are preserved.
[ColumnFilterConfig](https://rv-grid.com/guide/types/Interface.ColumnFilterConfig)
[FilterCollectionItem](https://rv-grid.com/guide/types/TypeAlias.FilterCollectionItem)
[MultiFilterItem](https://rv-grid.com/guide/types/Interface.MultiFilterItem)
## Configure blank values
The **Is blank** and **Is not blank** operations preserve the original source value instead of converting all falsy values to the same representation. The default policy is:
| Source value | Blank by default |
| --- | --- |
| `null` | Yes |
| An own property whose value is `undefined` | Yes |
| An empty string (`''`) | Yes |
| A missing own property | Yes |
| A whitespace-only string such as `' '` | No |
| An empty array (`[]`) | No |
| `false`, `0`, or `NaN` | No |
| Non-empty arrays and objects | No |
Set `blankSemantics` on the grid filter config to change this policy. Every field is optional:
```ts
grid.filter = {
blankSemantics: {
whitespaceOnlyString: true,
emptyArray: true,
null: true,
undefined: true,
emptyString: true,
missingProperty: true,
},
};
```
A column can override individual fields without repeating the grid policy. Column settings are merged field-by-field over the grid settings and the defaults:
```ts
grid.columns = [
{
prop: 'tags',
name: 'Tags',
filter: 'array',
// Keep [] as a non-blank value for this column only.
blankSemantics: { emptyArray: false },
},
{
prop: 'active',
name: 'Active',
filter: 'boolean',
},
];
```
Use `isBlank` for application-specific values. It runs after the configured rules and receives their result as `fallbackResult`:
```ts
grid.filter = {
blankSemantics: {
isBlank(value, context, fallbackResult) {
if (context.property === 'status' && value === 'N/A') {
return true;
}
return fallbackResult;
},
},
};
```
The callback receives the unparsed source `value` plus a context containing `model`, `column`, `property`, `sourceValue`, `parsedValue`, `hasOwnProperty`, and the effective `blankSemantics`. Inherited properties count as missing because `hasOwnProperty` is `false`.
Blank checks always use `sourceValue`, even when the column has a `cellParser`. Other built-in and custom filter operations continue to receive `parsedValue`. Configuring blank semantics does not coerce values for typed comparisons, so number, string, boolean, and array operators keep their existing strict behavior.
**Is not blank** is the exact inverse of the resolved blank predicate, including the result returned by `isBlank`.
## Customize filter names
Use `localization.filterNames` to replace the labels shown for built-in filter operations. For example, you can use shorter labels for the default **Is blank** and **Is not blank** operations:
```ts
import { filterNames } from '@revolist/revogrid';
grid.filter = {
localization: {
captions: {},
filterNames: {
...filterNames,
empty: 'Blank',
notEmpty: 'Not blank',
},
},
};
```
Spreading `filterNames` keeps all other built-in labels unchanged and satisfies the complete `FilterLocalization` mapping expected by TypeScript. Override any other operation id in the same object, such as `eq` for **Equal** or `contains` for **Contains**. The ids remain `empty` and `notEmpty` for compatibility with saved filters, regardless of the labels you display.
[FilterLocalization](https://rv-grid.com/guide/types/Interface.FilterLocalization)
## Restore saved filters
Use `collection` for simple saved filters:
```ts
grid.filter = {
collection: {
role: { type: 'eq', value: 'Admin' },
score: { type: 'gte', value: 80 },
},
};
```
Use `multiFilterItems` when a column needs several conditions:
```ts
grid.filter = {
multiFilterItems: {
score: [
{ id: 1, type: 'gte', value: 70 },
{ id: 2, type: 'lt', value: 95, relation: 'and' },
],
role: [
{ id: 3, type: 'eq', value: 'Admin' },
{ id: 4, type: 'eq', value: 'Editor', relation: 'or' },
],
},
};
```
## Filter parsed values
If a cell displays formatted text but filtering should use normalized data, add `cellParser` to the column or column type.
```ts
const columns = [
{
prop: 'total',
name: 'Total',
filter: 'number',
cellTemplate: (h, { model, prop }) =>
h('span', `$${Number(model[prop]).toLocaleString()}`),
cellParser: (model, column) => Number(model[column.prop] ?? 0),
},
];
```
See [Column Types and Formats](https://rv-grid.com/guide/column/types) and [Custom Cell Formats](https://rv-grid.com/guide/cell/custom-formats) for reusable parser patterns.
## Create a custom filter
Register custom operations through `customFilters`. The `columnFilterType` must match the column's `filter` value.
```ts
const matchesPriority = (value, expected = 'critical') =>
String(value).toLowerCase() === String(expected).toLowerCase();
matchesPriority.extra = 'input';
grid.columns = [
{ prop: 'ticket', name: 'Ticket' },
{ prop: 'priority', name: 'Priority', filter: 'ticketPriority' },
];
grid.filter = {
include: ['isHighPriority'],
customFilters: {
isHighPriority: {
columnFilterType: 'ticketPriority',
name: 'High priority',
func: matchesPriority,
},
},
};
```
The filter function receives the parsed cell value and the extra value from the filter panel. `func.extra = 'input'` asks the panel to render an input for that operation. The filter API also supports `datepicker` or a custom extra-field renderer for specialized UIs.
[CustomFilter](https://rv-grid.com/guide/types/Interface.CustomFilter)
### Choose the right extension point
Filtering can be extended at several levels without replacing the whole plugin:
- Use `cellParser` to normalize a stored value before built-in or custom operations evaluate it.
- Use `customFilters` to add a reusable operation that returns `true` or `false` for each row.
- Use `beforefilterapply` to inspect, rewrite, or delegate the requested filter before evaluation starts.
- Use `beforefiltertrimmed` when your application needs final control over the physical row indexes that will be hidden.
Custom filter functions are synchronous predicates. RevoGrid may call them once per row for each active condition, so keep them pure and fast: avoid network requests, DOM work, large allocations, and shared-state mutations. Do not declare a custom predicate `async` or return a `Promise`; a promise is not a deferred boolean filter result.
### How asynchronous filtering works
For large local datasets, RevoGrid can yield between batches of synchronous predicate calls. The overall operation can continue across browser tasks while every individual custom predicate remains simple and synchronous. If a newer filter or source arrives, stale batched work can be discarded before it changes the visible result.
When filtering genuinely requires asynchronous work—such as an API request, database query, or permission service—prevent the local operation in `beforefilterapply` and let your data controller load the matching rows into `source`. The controller should cancel or ignore stale requests and guard against requesting the same filter again when the remote source is assigned. See [Remote filtering](https://rv-grid.com/guide/server-side-data#remote-filtering) for the recommended flow.
## Event hooks
Filtering is event-driven. Use these hooks when your app needs to observe, rewrite, or replace filtering behavior.
```ts
grid.addEventListener('beforefilterapply', event => {
const { collection } = event.detail;
for (const prop of Object.keys(collection)) {
if (collection[prop].value === '') {
delete collection[prop];
}
}
});
grid.addEventListener('beforefiltertrimmed', event => {
console.log('Rows about to be hidden', event.detail.itemsToFilter);
});
```
Useful events:
| Event | When to use it |
| --- | --- |
| `beforefilterapply` | Inspect or modify the filter collection before rows are evaluated. |
| `beforefiltertrimmed` | Inspect or replace the physical row indexes that will be hidden. |
| `beforetrimmed` | Intercept trimming generally, including filtering-driven trimming. |
| `aftertrimmed` | React after visible rows have changed. |
| `filterconfigchanged` | Persist new filter config when the `filter` prop changes. |
For the full event table, see [API: Events](https://rv-grid.com/guide/api/events) and [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid). For the filtering event flow, see [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide#filtering).
When the backend must own the filtered dataset, intercept `beforefilterapply`, prevent local trimming, and reload `source` from your server. See [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data#remote-filtering).
## Read filtered rows
After a filter is applied, use `getVisibleSource()` when the application needs the current visible dataset.
```ts
const visibleRows = await grid.getVisibleSource();
const visibleEmails = visibleRows.map(row => row.email);
```
See [Programmatic Control](https://rv-grid.com/guide/programmatic-control#read-visible-rows).
## Pro filtering
The open-source filter plugin is a strong base: text and number operations, custom functions, localization, saved state, and event hooks are all available in the Community package. RevoGrid Pro builds on the same API and makes filtering feel closer to a full spreadsheet or back-office data product.
Import the Pro plugins and stylesheet, then add the plugins to the grid `plugins` list. `AdvanceFilterPlugin` adds selection, slider, quick-search, and date filter operations; `FilterHeaderPlugin` adds always-visible header inputs.
```ts
import {
AdvanceFilterPlugin,
FilterHeaderPlugin,
FIlTER_SELECTION,
FIlTER_SLIDER,
} from '@revolist/revogrid-pro';
import '@revolist/revogrid-pro/dist/revogrid-pro.css';
const plugins = [AdvanceFilterPlugin, FilterHeaderPlugin];
const columns = [
{ prop: 'city', name: 'City', filter: ['string', FIlTER_SELECTION] },
{ prop: 'status', name: 'Status', filter: [FIlTER_SELECTION] },
{ prop: 'createdAt', name: 'Created', filter: ['date'] },
{ prop: 'amount', name: 'Amount', filter: ['number', FIlTER_SLIDER] },
{ prop: 'owner', name: 'Owner', filter: ['input'] },
];
grid.plugins = plugins;
grid.columns = columns;
grid.filter = true;
```
### Advanced Selection Filtering
Selection filtering gives users a fast pick-list for repeated values such as status, city, category, owner, country, or product type. It is ideal for operational grids where users already know the value they want and should not have to type exact text into a generic input.
### Advanced Slider Filtering
Slider filtering adds a range-based control for numeric columns. It works well for prices, quantities, ratings, scores, budgets, and other bounded numeric values where users want to narrow a dataset visually instead of entering `gte` and `lte` values manually.
### Header Input Filtering
Header input filtering keeps filter inputs visible directly in the header row. This is useful for dense back-office screens where filtering is a constant workflow and users need to scan, type, adjust, and compare without opening a popup for every column.
### Date Filter
Date filtering adds date-aware operations for temporal data such as schedules, orders, logs, audit records, deadlines, and activity history. Users can filter by exact dates, ranges, and common date windows without writing custom date parsing logic.
### Multi-Filtering
Multi-filtering lets users combine several conditions per field with clearer `and` / `or` workflows. It is especially useful when a single column needs layered logic, for example "amount is greater than 100 and less than 500" or "status is open or pending".
These Pro filters are valuable when users live in the grid all day: they can narrow a large dataset from several angles, combine filters without leaving the table, and keep the interaction fast because the Pro features plug into RevoGrid's existing virtualized rendering and filter events.
Start with [RevoGrid Pro features](https://rv-grid.com/pro/#features), or open the business demos that use Pro workflows:
- [Pivot analytics demo](https://rv-grid.com/pivot/)
## Related docs
- [JavaScript filtering demo](https://rv-grid.com/guide/demos/js/js.filtering)
- [Column Types and Formats](https://rv-grid.com/guide/column/types)
- [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data)
- [Programmatic Control](https://rv-grid.com/guide/programmatic-control)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide#filtering)
- [API: Events](https://rv-grid.com/guide/api/events)
- [API: RevoGrid](https://rv-grid.com/guide/api/revoGrid)
- [API: ColumnFilterConfig](https://rv-grid.com/guide/types/Interface.ColumnFilterConfig)
---
# RevoGrid Plugin System
Source: https://rv-grid.com/guide/plugin
Description: Learn how to build RevoGrid plugins with BasePlugin, providers, event subscriptions, dispatching, lifecycle cleanup, and extension points.
# Plugin System
[Interface: PluginBaseComponent](https://rv-grid.com/guide/types/Interface.PluginBaseComponent)
[TypeAlias: PluginProviders](https://rv-grid.com/guide/types/TypeAlias.PluginProviders)
RevoGrid offers a powerful and flexible plugin system that allows you to extend its functionality. By creating custom plugins, you can add new features, modify existing behavior, and integrate RevoGrid with other libraries or frameworks.
## Creating a Plugin
All plugins in RevoGrid extend from the `BasePlugin` class, which provides a minimal starting core and utility methods for working with the RevoGrid component.
### BasePlugin Class
The `BasePlugin` class serves as a foundational layer for creating plugins. Here's an overview of its interface and capabilities:
```typescript
/**
* Base layer for plugins
* Provide minimal starting core for plugins to work
* Extend this class to create plugin
*/
export class BasePlugin implements PluginBaseComponent {
readonly subscriptions: Record void> = {};
constructor(public revogrid: HTMLRevoGridElement, public providers: PluginProviders) {}
/**
* Subscribe to an event in the RevoGrid component.
* @param eventName - event name to subscribe to in RevoGrid component (e.g. 'beforeheaderclick')
* @param callback - callback function for the event
*/
addEventListener(eventName: string, callback: (e: CustomEvent) => void): void;
/**
* Subscribe to a property change in the RevoGrid component.
* You can return false in the callback to prevent the default value set.
* @param prop - property name
* @param callback - callback function
* @param immediate - trigger callback immediately with current value
*/
watch(
prop: string,
callback: (arg: T) => boolean | void,
config?: Partial
): void;
/**
* Remove an event listener.
* @param eventName - event name
*/
removeEventListener(eventName: string): void;
/**
* Emit an event from the RevoGrid component.
* The event can be cancelled by calling event.preventDefault() in the callback.
* @param eventName - event name
* @param detail - event detail
*/
emit(eventName: string, detail?: any): CustomEvent;
/**
* Clear all subscriptions.
*/
clearSubscriptions(): void;
/**
* Destroy the plugin and clear all subscriptions.
*/
destroy(): void;
}
```
### Plugin Lifecycle
1. **Initialization**: When a plugin is created, it initializes with references to the RevoGrid component and its providers.
2. **Event Subscription**: Plugins can subscribe to RevoGrid events using `addEventListener`.
3. **Property Watchers**: Plugins can watch for property changes using `watch`.
4. **Event Emission**: Plugins can emit custom events using `emit`.
5. **Cleanup**: Plugins should clean up their subscriptions using `clearSubscriptions` and `destroy` methods.
### Dispatching Events
In RevoGrid, custom events are dispatched to elements using the `dispatch` and `dispatchByEvent` functions. These functions are essential for creating responsive and interactive plugins in RevoGrid, ensuring that events propagate correctly to the top level of the application.
[Read more here](https://rv-grid.com/guide/types/README#dispatch-)
### Example Plugin
Here's an example of a simple plugin that logs when a cell is focused:
```typescript
class CellLogger extends BasePlugin {
constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders) {
super(revogrid, providers);
this.addEventListener('beforecellfocus', this.handleCellFocus);
}
private handleCellFocus = (e: CustomEvent) => {
console.log('Cell focused:', e.detail);
};
}
// Usage
const gridElement = document.querySelector('revo-grid');
gridElement.plugins.push(CellClickLogger);
```
## Plugin Providers
For more advanced plugins, you might need to interact with these providers directly.
The `PluginProviders` type includes several providers that give access to different parts of RevoGrid's internal state:
- **Data Manipulation**: Use the `data` provider to manipulate the data in the grid.
- **Dimension Handling**: Use the `dimension` provider to manage row and column dimensions.
- **Selection Management**: Use the `selection` provider to handle cell and row selections.
- **Column Management**: Use the `column` provider to manage column data and properties.
- **Viewport Management**: Use the `viewport` provider to handle scrolling and viewport rendering.
## Conclusion
The RevoGrid plugin system provides a powerful way to extend and customize the grid's functionality. By leveraging the `BasePlugin` class and the provided utility methods, you can create robust plugins that enhance the capabilities of RevoGrid.
If you have any questions or need further assistance, feel free to reach out to the RevoGrid community or check our [RevoGrid Pro](https://rv-grid.com/pro).
---
# Security
Source: https://rv-grid.com/guide/security
# Security
🛡️ **RevoGrid** is a JavaScript library designed to ensure your application meets your security requirements.
## Content Security Policy (CSP)
The basic information on Content Security Policy can be found on the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
## Security Vulnerability Testing
[](https://sonarcloud.io/summary/new_code?id=revolist_revogrid)
Applications using RevoGrid may need to pass security tests before production deployment. RevoGrid is tested for a variety of security vulnerabilities using the SonarQube automatic security testing tool. SonarQube evaluates security using well-established standards such as CWE, SANS Top 25, and OWASP Top 10.
### SonarQube Results
The SonarQube security test results for our main NPM packages are available, ensuring that RevoGrid maintains high security standards.
[](https://sonarcloud.io/summary/new_code?id=revolist_revogrid)
---
# Server-side data, pagination, sorting, and filtering
Source: https://rv-grid.com/guide/server-side-data
Description: Build a production server-side data layer for RevoGrid with remote pagination, infinite loading, sorting, filtering, grouping, request cancellation, caching, and edit sync.
You Data Grid can render large local datasets efficiently, but in production often cannot load the whole dataset into the browser. Your backend may own permissions, search, joins, sorting, filtering, grouping, totals, audit logs, and edit validation.
This guide describes an application-owned server-side data layer around RevoGrid. It does not add a new grid API. The grid still receives rows through `source`, columns through `columns`, and user intent through events. Your app owns the remote query, cache, loading state, error state, and persistence.
::: info Use this pattern when
- the complete dataset is too large for browser memory
- sorting or filtering must match backend authorization rules
- edits must be validated, audited, or merged by the server
- users need pagination, infinite loading, or grouped remote data
- stale network responses must not overwrite newer user intent
:::
## Recommended model
Treat RevoGrid as the viewport and interaction layer. Treat your data controller as the source of truth for the active remote window.
```txt
user action -> RevoGrid event -> app data controller -> backend request -> grid.source
```
The important boundary is that full `source` replacement means "the remote dataset window changed". Do not recreate `source` after every cell edit just to mirror local state. For edit syncing patterns, see [Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync).
## Backend query
Use one query shape for page loads, infinite-scroll windows, sorting, filtering, quick search, and grouping. Keep the request explicit and serializable so it can become a cache key.
```ts
type SortOrder = 'asc' | 'desc';
type GridQuery = {
offset: number;
limit: number;
sort?: Record;
filter?: Record;
group?: { by: string[]; route?: string[] };
search?: string;
};
type GridResponse = {
rows: Row[];
total?: number;
hasMore?: boolean;
};
```
Use `total` when the backend can count cheaply. Use `hasMore` when counting is expensive or the dataset is streaming.
For edits, use a separate mutation endpoint. Do not mix row loading and cell persistence into one route.
```ts
type GridEditRequest = {
rowId: string | number;
field: string;
value: unknown;
previousValue?: unknown;
};
type GridEditResponse = {
accepted: boolean;
row?: Row;
message?: string;
};
```
The backend should return the canonical row when it normalizes values, applies business rules, or writes server-generated fields such as `updatedAt`.
## Pagination and infinite scrolling
Server-side pagination uses a fixed `page` and `limit`:
```txt
page 0 -> offset 0, limit 100
page 1 -> offset 100, limit 100
```
Infinite scrolling uses the same backend contract, but the trigger comes from the scroll position instead of a page button:
```txt
visible range approaches end -> request next offset -> append or replace window
```
Choose the behavior based on product needs:
| Pattern | Use it when | Grid source strategy |
| --- | --- | --- |
| Pagination | Users need stable pages, URLs, or exports by page | Replace `source` with the requested page. |
| Infinite scrolling | Users scan a long operational feed | Load windows by offset and keep enough rows for smooth scrolling. |
| Pro Infinity Scroll | You want plugin-managed chunk loading and buffer cleanup | Start from [RevoGrid Pro](https://rv-grid.com/pro/). |
The backend contract should be the same either way. That keeps filtering, sorting, caching, and export code reusable.
## Remote sorting
For server-authoritative sorting, mark columns as sortable so users get the normal header interaction. Then intercept `beforesortingapply`, call `event.preventDefault()`, and reload from the backend.
```ts
grid.columns = [
{ prop: 'name', name: 'Name', sortable: true },
{ prop: 'createdAt', name: 'Created', sortable: true },
];
```
Use the event to send `{ [column.prop]: order }` to the backend. If you support multi-sort, keep the full sort object in the controller and honor the event's `additive` flag.
## Remote filtering
For server-authoritative filtering, enable the normal filter UI, intercept `beforefilterapply`, prevent local trimming, and send the collection to the backend.
```ts
grid.filter = true;
grid.addEventListener('beforefilterapply', event => {
event.preventDefault();
void controller.setFilter(event.detail.collection);
});
```
The filter collection uses RevoGrid's column props and filter operation ids. Your API can accept this shape directly or translate it to a backend-specific query language.
## Remote grouping
Client-side grouping is appropriate when the browser owns the complete dataset. Server-side grouping is different: the backend must own group keys, child routes, counts, aggregates, sorting, filtering, and lazy expansion.
Use a route-based query shape:
```ts
const query: GridQuery = {
offset: 0,
limit: 100,
group: { by: ['country', 'city'], route: ['Germany'] },
sort: { revenue: 'desc' },
filter: { status: { type: 'eq', value: 'active' } },
};
```
For production grouping with lazy expansion and route cache behavior, start from [RevoGrid Pro](https://rv-grid.com/pro/).
## Cancellation, races, and cache keys
Remote grid UIs create overlapping requests. A user can type a filter, click sort, change page, and edit a row before the first response returns.
Use all three safeguards:
- Abort the previous request with `AbortController`.
- Track a monotonically increasing request id and ignore stale responses.
- Build cache keys from the complete query: `{ page, limit, sort, filter, group, search }`.
Do not key the cache only by page number. Page 2 of "all rows" is not the same data as page 2 after filtering by status or sorting by date.
For shared caches, normalize object key order before serializing. The example uses `JSON.stringify(query)` because it builds the query in a stable order in one place.
## Optimistic edits and backend sync
RevoGrid applies cell edits before `afteredit` fires. That makes optimistic saves straightforward:
1. Let the grid apply the local edit.
2. Send `{ rowId, field, value, previousValue }` to the backend from `afteredit`.
3. If the backend accepts and returns a canonical row, merge it into the model.
4. If the backend rejects, restore the previous value with `setDataAt`.
5. Clear remote caches that may contain the old row.
Use `beforeedit` when a rule can be decided locally and the edit should be blocked before it changes the model. Use `afteredit` when the server is the authority and the UI should feel responsive while the save is in flight.
## Loading and error states
Keep loading and error state in the controller or app shell:
- disable pagination buttons while the current page is loading
- show a small overlay or status row during the first load
- keep old rows visible during background refresh when possible
- show retry controls for failed loads
- show field-level or row-level messages for rejected edits
Avoid network calls or loading state inside cell templates. Cell renderers run as part of virtual rendering and should stay cheap. See [RevoGrid Performance and Virtualization](https://rv-grid.com/guide/performance).
## Checklist
- Keep `columns` stable and replace `source` only when the remote window changes.
- Use `beforesortingapply` for remote sorting.
- Use `beforefilterapply` for remote filtering.
- Cancel in-flight requests and ignore stale responses.
- Include sort, filter, group, search, offset, and limit in cache keys.
- Keep loading and error UI outside cell renderers.
- Use `afteredit` for optimistic save and rollback.
- Let the backend own server grouping, counts, aggregates, and permissions.
## Related guides
- [Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync)
- [RevoGrid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [RevoGrid Best Practices](https://rv-grid.com/guide/patterns)
- [RevoGrid Filtering](https://rv-grid.com/guide/filters)
- [Data Grid Sorting](https://rv-grid.com/guide/sorting)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
---
# Slots
Source: https://rv-grid.com/guide/slots
# Slots
RevoGrid uses slots, a feature of StencilJS, to allow you to inject custom content into specific parts of the grid. This provides flexibility for customizing the appearance and functionality of your grid.
## Available Slots
### Data Slots
Data slots allow you to add extra elements to the main data area of the grid.
- **Format**: `data-{column-type}-{row-type}`
- **Example**: `data-rgCol-rgRow`
This slot applies additional elements within the `` component, which is responsible for rendering the main data cells.
```html
Custom Content
```
### Focus Slots
Focus slots enable you to add elements to the focus layer of the grid, which is used to indicate the currently focused cell or range.
- **Format**: `focus-{column-type}-{row-type}`
- **Example**: `focus-rgCol-rgRow`
This slot applies extra elements within the `` component, enhancing the visual representation of the focused cells.
```html
Focused Content
```
## Examples
Here are some examples of how to use these slots:
### Data Slot Example
Add custom content to the main data cells:
```html
Custom Data Element
```
### Focus Slot Example
Add custom content to the focus layer:
```html
Focus Element
```
By utilizing these slots, you can extend and customize the functionality and appearance of RevoGrid to better fit your application's needs.
For more details, please refer to the [API documentation](https://rv-grid.com/guide/api/revoGrid).
---
# Data Grid Sorting
Source: https://rv-grid.com/guide/sorting
Description: Configure RevoGrid sorting with sortable columns, default sort order, custom compare functions, and sorting lifecycle events.
Adding sorting to your data grid is quite straightforward:
- **Add `sortable` property to the column**: Enables sorting to be triggered on header click.
- **Add `order` property to the column**: Specifies the default sorting order, either `asc` (ascending) or `desc` (descending).
- **(Optional) Add `cellCompare` method to the column**: Provides custom sorting logic.
### Example
Here’s an example of how to add sorting to your columns:
```javascript
const columns = [
{
name: 'Name',
prop: 'name',
sortable: true, // Enables sorting
order: 'asc', // Default sorting order
cellCompare: (prop, a, b) => { // Custom sorting logic
const av = a[prop]?.toString().toLowerCase();
const bv = b[prop]?.toString().toLowerCase();
return av - bv;
}
},
];
const items = [
{ name: 'John Doe', age: 30 },
{ name: 'Jane Smith', age: 25 }
];
grid.columns = columns;
grid.source = items;
```
## Sorting Events
:::tip
For more details, please refer to the API section and the column data schema interfaces.
:::
- **`beforesorting`** - `CustomEvent<{ column: ColumnRegular, order: 'desc' | 'asc' }>` - Triggered after a header click and before sorting starts. Use `e.preventDefault()` to prevent any further sorting chain. If this event is prevented, `beforesortingapply` will not be triggered.
- **`beforesortingapply`** - `CustomEvent<{ column: ColumnRegular, order: 'desc' | 'asc' }>` - Triggered before the sorting data is applied. Use `e.preventDefault()` to avoid the default data sorting and implement your own sorting logic.
- **`aftersortingapply`** - `CustomEvent<{ sorting?: SortingOrder, sortingColumns?: Record | undefined>, sortingOrder?: ColumnProp[], types: DimensionRows[] }>` - Triggered after sorting has been applied and completed. Use `sortingColumns` to inspect the columns that sorting was applied to and `sorting` for the applied order.
For server-authoritative sorting, intercept `beforesortingapply`, call `e.preventDefault()`, and reload `source` from your backend with the requested sort state. See [Server-side data, pagination, sorting, and filtering](https://rv-grid.com/guide/server-side-data#remote-sorting).
## Lifecycle
1. **`@event` `beforesorting`** - Triggered when sorting is initiated. At this point, no changes have been made yet. This event can be triggered by sorting from a column or from the source. If the sorting type is from rows, the column will be undefined.
2. **`@method` `updateColumnSorting`** - This method updates the column sorting icon on the grid and the column itself, but the data remains unchanged.
3. **`@event` `beforesortingapply`** - Triggered before the sorting data is applied to the data source. You can prevent this event to stop the data from being sorted. This event is only called when sorting is initiated from a column click.
4. **`@event` `aftersortingapply`** - Triggered after the sorting has been applied and completed. The event detail provides the final sorting state, sorting column metadata, sorting priority, and affected row store types.
---
# Single file bundle
Source: https://rv-grid.com/guide/standalone
# Single file bundle
RevoGrid also offers a single file bundle without the polyfills and other additional functionality included in the default output.
You would need additional dependency to load RevoGrid as standalone esm module.
::: code-group
```npm
npm i @stencil/core
```
```pnpm
pnpm add @stencil/core
```
```yarn
yarn add @stencil/core
```
```bun
bun add @stencil/core
```
:::
Now you can import `RevoGrid` into your app:
```js
import { defineCustomElement } from "@revolist/revogrid/standalone";
// A utility defineCustomElement() function is exported from esm file of the output directory.
// This function can be used to quickly define all RevoGrid components in a project on the custom elements registry.
defineCustomElement();
import { defineCustomElement as defineFilterPanel } from '@revolist/revogrid/standalone/revogr-filter-panel.js';
// Filter is defined as a standalone component plugin and should be imported here
defineFilterPanel?.();
```
Please note that this standalone output does not automatically define the custom elements or apply any polyfills which is why we’re defining the custom element above ourselves.
For more details, please see [Stencil.js documentation](https://stenciljs.com/docs/custom-elements).
## Standalone JavaScript Data Grid Starter
[](https://codesandbox.io/p/sandbox/rg-custom-sizes-per-row-forked-dq2mjk)
---
# SSR (Server side rendering)
Source: https://rv-grid.com/guide/ssr
# SSR (Server side rendering)
RevoGrid library includes a hydrate app that is a bundle of the same components, but compiled so that they can be hydrated on a NodeJS server and generate static HTML and CSS. To get started, import the hydrate app into your server’s code like so:
```js
import hydrate from "@revolist/revogrid/hydrate"
```
If you are using for example [Eleventy](https://www.11ty.dev/), you could now add a transform into `.eleventy.js` configuration file that takes content as an input and processes it using RevoGrid’s hydrate app:
```js
eleventyConfig.addTransform("hydrate", async(content, outputPath) => {
if (process.env.ELEVENTY_ENV == "production") {
if (outputPath.endsWith(".html")) {
try {
const results = await hydrate.renderToString(content, {
clientHydrateAnnotations: true,
removeScripts: false,
removeUnusedStyles: false
})
return results.html
} catch (error) {
return error
}
}
}
return content
})
```
The above transform gives you server side rendered components that function without JavaScript. Please note that you need to separately pre-render the content for each theme you want to support.
---
# RevoGrid Themes
Source: https://rv-grid.com/guide/theme
Description: Use built-in RevoGrid themes, inheritable CSS variables, and typed per-grid custom theme definitions.
# Themes
RevoGrid includes five built-in themes and supports two additive customization paths:
- CSS custom properties for local or application-wide styling
- typed `ThemeDefinition` presets for reusable, per-grid themes
Both paths use the existing `theme` property. A custom theme name stays reflected in the `theme` attribute, so ordinary CSS selectors remain available as an advanced escape hatch.
## Built-in themes
| Theme | Structure | Color scheme | Default row height |
| -------------- | --------- | ------------ | -----------------: |
| `default` | Default | Light | 27 px |
| `material` | Material | Light | 42 px |
| `compact` | Compact | Light | 32 px |
| `darkMaterial` | Material | Dark | 42 px |
| `darkCompact` | Compact | Dark | 32 px |
```js
const grid = document.querySelector('revo-grid')
grid.theme = 'material'
```
Changing `theme` at runtime updates the structure, color scheme, tokens, and default density together. After application, RevoGrid emits `afterthemechanged` with the normalized theme name in `event.detail`.
## CSS-only customization
CSS variables inherit normally. Define them on an application container to affect all descendant grids, or on one grid for an instance-specific override.
```css
.billing-screen {
--revo-grid-font-family: Inter, system-ui, sans-serif;
--revo-grid-primary: #6d4aff;
}
revo-grid[theme='billing'] {
--revo-grid-background: #fbfaff;
--revo-grid-header-bg: #f0edff;
--revo-grid-header-color: #241c45;
--revo-grid-selection-border: #6d4aff;
}
```
```js
const grid = document.querySelector('revo-grid')
grid.theme = 'billing'
```
Any non-empty name is valid. If no typed definition exists, the name remains reflected and RevoGrid uses `default` layout metadata. A blank name normalizes to `default`.
## Typed reusable themes
Use `defineTheme` for type checking and autocomplete. A custom theme can extend a built-in theme or another custom definition registered on the same grid.
```ts
import { defineTheme, type ThemeDefinition } from '@revolist/revogrid'
export const billingTheme = defineTheme({
name: 'billing',
extends: 'darkMaterial',
defaultRowSize: 36,
tokens: {
primary: '#9b8cff',
background: '#17151f',
text: '#f4f1ff',
headerBg: '#242031',
selectionBorder: '#b8adff',
filterPanelBg: '#242031',
filterPanelText: '#f4f1ff',
},
} satisfies ThemeDefinition)
const grid = document.querySelector('revo-grid')!
grid.themeDefinitions = [billingTheme]
grid.theme = billingTheme.name
```
`themeDefinitions` is a JavaScript property containing objects. Do not serialize it into an HTML attribute. Built-in names are reserved, and the last definition wins when the array contains duplicate custom names.
Invalid or missing parents, non-positive `defaultRowSize` values, invalid color schemes, and unknown token keys are ignored in favor of default or inherited values. Cyclic inheritance is detected and falls back to the built-in `default` metadata for the affected child while keeping that child's valid overrides.
### Structure and color scheme
`extends` selects the parent theme. The child inherits its structural preset, color scheme, density, and tokens. `colorScheme`, `defaultRowSize`, and child tokens override their inherited values without coupling behavior to the custom theme name.
```ts
const highContrastCompact = defineTheme({
name: 'highContrastCompact',
extends: 'compact',
colorScheme: 'dark',
tokens: {
background: '#000',
text: '#fff',
cellBorder: '#777',
},
})
```
Darkness is resolved from `colorScheme`; RevoGrid does not infer it from words in `name`.
### Extend another custom theme
Register the parent and child definitions on the same grid. Definition order does not affect inheritance; duplicate names still use the last definition in the array.
```ts
const productTheme = defineTheme({
name: 'product',
extends: 'material',
defaultRowSize: 38,
tokens: {
primary: '#2563eb',
background: '#f8fafc',
text: '#0f172a',
headerBg: '#e2e8f0',
},
})
const billingTheme = defineTheme({
name: 'billing',
extends: productTheme.name,
tokens: {
primary: '#7c3aed',
headerBg: '#ede9fe',
},
})
grid.themeDefinitions = [productTheme, billingTheme]
grid.theme = billingTheme.name
```
`billing` inherits the material structure, 38 px density, background, and text from `product`, then replaces only `primary` and `headerBg`.
## Precedence
Theme values resolve in this order, from lowest to highest priority:
1. built-in fallback values at the root of the inheritance chain
2. inherited or grid-level CSS custom properties
3. ancestor `ThemeDefinition` tokens, from root to immediate parent
4. tokens from the active child `ThemeDefinition`
5. a positive `rowSize` property for row geometry
This means application CSS is a convenient default, while a reusable typed preset remains deterministic on the grid using it.
## Density and row sizes
`defaultRowSize` belongs to the theme definition. The public `rowSize` property is an explicit grid override:
```ts
grid.rowSize = 44
grid.theme = 'compact'
grid.theme = 'material'
// Rows remain 44 px across both switches.
grid.rowSize = 0
// The active theme's defaultRowSize applies again.
```
Custom entries in `rowDefinitions` remain in force when the theme density changes. RevoGrid updates virtual geometry only when the effective row size changes; color-only token changes do not reset row geometry.
## Runtime updates
```ts
grid.addEventListener('afterthemechanged', (event) => {
console.log(event.detail) // normalized string name
})
grid.theme = 'billing'
grid.themeDefinitions = [
{
...billingTheme,
tokens: { ...billingTheme.tokens, primary: '#ffb86b' },
},
]
```
Assign a new `themeDefinitions` array when changing a definition. This matches React, Vue, Angular, and Svelte change-detection conventions and ensures the grid reapplies the active preset.
Definitions are registered per grid. Two grids may use the same custom name with different definitions without leaking styles or configuration between instances.
## Modern preset collection
RevoGrid exports five opt-in presets built with the same public `ThemeDefinition` API. They are ordinary definitions rather than additional structural modes, so applications only ship and register the designs they use.
| Preset | Direction | Base | Row height |
| ------------------ | ----------------------------------------------------------- | -------------- | ---------: |
| `ocean` | Airy blue and slate for light workspaces | `material` | 38 px |
| `midnight` | Deep navy with cyan and violet accents | `darkMaterial` | 40 px |
| `aurora` | Compact graphite with luminous green states | `darkCompact` | 34 px |
| `highContrast` | Strong light surfaces, borders, and blue focus states | `material` | 40 px |
| `highContrastDark` | Near-black surfaces with yellow and cyan interaction states | `darkMaterial` | 40 px |
Register the full collection:
```ts
import { modernThemeDefinitions } from '@revolist/revogrid'
grid.themeDefinitions = modernThemeDefinitions
grid.theme = 'midnight'
```
Or import one independently to keep configuration explicit:
```ts
import { oceanTheme } from '@revolist/revogrid'
grid.themeDefinitions = [oceanTheme]
grid.theme = oceanTheme.name
```
Curated presets can also serve as parents. Register the preset alongside the child definition:
```ts
import { defineTheme, oceanTheme } from '@revolist/revogrid'
const brandedOcean = defineTheme({
name: 'brandedOcean',
extends: oceanTheme.name,
tokens: {
primary: '#db2777',
buttonBg: '#db2777',
},
})
grid.themeDefinitions = [oceanTheme, brandedOcean]
grid.theme = brandedOcean.name
```
For accessibility-focused registration, import only the dedicated collection:
```ts
import { highContrastThemeDefinitions } from '@revolist/revogrid'
grid.themeDefinitions = highContrastThemeDefinitions
grid.theme = 'highContrastDark'
```
The exports are `oceanTheme`, `midnightTheme`, `auroraTheme`, `highContrastTheme`, `highContrastDarkTheme`, `highContrastThemeDefinitions`, and `modernThemeDefinitions`. The high-contrast presets provide stronger default differentiation, but application overrides and custom cell renderers still need their own accessibility review. Since definitions remain per-grid, their names can be replaced by a later definition in your own array without affecting another grid.
## Framework examples
All framework wrappers pass `themeDefinitions` as an object-valued property.
::: code-group
```tsx [React]
import { RevoGrid } from '@revolist/react-datagrid'
import { defineTheme } from '@revolist/revogrid'
const themes = [
defineTheme({
name: 'brand',
extends: 'material',
tokens: { primary: '#6d4aff', headerBg: '#f0edff' },
}),
]
export function Grid() {
return (
)
}
```
```vue [Vue 3]
```
```ts [Angular]
import { Component } from '@angular/core'
import { RevoGrid, defineTheme } from '@revolist/angular-datagrid'
@Component({
standalone: true,
imports: [RevoGrid],
template: `
`,
})
export class AppComponent {
themes = [
defineTheme({
name: 'brand',
extends: 'material',
tokens: { primary: '#6d4aff', headerBg: '#f0edff' },
}),
]
}
```
```svelte [Svelte]
```
```python [Dash]
from dash_datagrid import RevoGrid
RevoGrid(
columns=columns,
source=rows,
theme="brand",
themeDefinitions=[{
"name": "brand",
"extends": "material",
"tokens": {
"primary": "#6d4aff",
"headerBg": "#f0edff",
},
}],
style={"height": 420},
)
```
:::
## Public theme tokens
Token keys are type checked by `ThemeTokens`. Each key maps to an inheritable CSS custom property.
### Foundation and grid states
| Token | CSS custom property |
| -------------------- | --------------------------------- |
| `primary` | `--revo-grid-primary` |
| `primaryTransparent` | `--revo-grid-primary-transparent` |
| `background` | `--revo-grid-background` |
| `foreground` | `--revo-grid-foreground` |
| `divider` | `--revo-grid-divider` |
| `shadow` | `--revo-grid-shadow` |
| `text` | `--revo-grid-text` |
| `border` | `--revo-grid-border` |
| `headerBg` | `--revo-grid-header-bg` |
| `headerColor` | `--revo-grid-header-color` |
| `headerBorder` | `--revo-grid-header-border` |
| `headerFocusedBg` | `--revo-grid-header-focused-bg` |
| `headerHoverBg` | `--revo-grid-header-hover-bg` |
| `cellBorder` | `--revo-grid-cell-border` |
| `cellVerticalBorder` | `--revo-grid-cell-vertical-border` |
| `focusedBg` | `--revo-grid-focused-bg` |
| `rowHover` | `--revo-grid-row-hover` |
| `rowHeadersBg` | `--revo-grid-row-headers-bg` |
| `rowHeadersColor` | `--revo-grid-row-headers-color` |
| `cellDisabledBg` | `--revo-grid-cell-disabled-bg` |
`cellVerticalBorder` is transparent by default for material and compact structures. Set it in a custom definition or with its CSS variable to opt into vertical separators; the `highContrastDark` preset enables it automatically.
### Typography and spacing
| Token | CSS custom property |
| --------------------- | ----------------------------------- |
| `fontFamily` | `--revo-grid-font-family` |
| `fontSize` | `--revo-grid-font-size` |
| `headerHeight` | `--revo-grid-header-height` |
| `headerFontSize` | `--revo-grid-header-font-size` |
| `headerFontWeight` | `--revo-grid-header-font-weight` |
| `headerTextTransform` | `--revo-grid-header-text-transform` |
| `headerTextAlign` | `--revo-grid-header-text-align` |
| `cellTextAlign` | `--revo-grid-cell-text-align` |
| `headerPadding` | `--revo-grid-header-padding` |
| `cellPadding` | `--revo-grid-cell-padding` |
### Selection, autofill, and resize
| Token | CSS custom property |
| -------------------------- | ---------------------------------------- |
| `selectionBorder` | `--revo-grid-selection-border` |
| `selectionBg` | `--revo-grid-selection-bg` |
| `autofillHandleBg` | `--revo-grid-autofill-handle-bg` |
| `autofillHandleBorder` | `--revo-grid-autofill-handle-border` |
| `rangeHandleBg` | `--revo-grid-range-handle-bg` |
| `temporaryRangeBorder` | `--revo-grid-temporary-range-border` |
| `temporarySelectionBorder` | `--revo-grid-temporary-selection-border` |
| `headerResizeHover` | `--revo-grid-header-resize-hover` |
### Filter panel
| Token | CSS custom property |
| -------------------------------- | ------------------------------------------------ |
| `filterPanelBg` | `--revo-grid-filter-panel-bg` |
| `filterPanelBorder` | `--revo-grid-filter-panel-border` |
| `filterPanelShadow` | `--revo-grid-filter-panel-shadow` |
| `filterPanelInputBg` | `--revo-grid-filter-panel-input-bg` |
| `filterPanelDivider` | `--revo-grid-filter-panel-divider` |
| `filterPanelSelectBorder` | `--revo-grid-filter-panel-select-border` |
| `filterPanelSelectBorderHover` | `--revo-grid-filter-panel-select-border-hover` |
| `filterPanelReorderAccent` | `--revo-grid-filter-panel-reorder-accent` |
| `filterPanelReorderColor` | `--revo-grid-filter-panel-reorder-color` |
| `filterPanelText` | `--revo-grid-filter-panel-text` |
| `filterPanelMutedText` | `--revo-grid-filter-panel-muted-text` |
| `filterPanelFocusRing` | `--revo-grid-filter-panel-focus-ring` |
| `filterPanelIcon` | `--revo-grid-filter-panel-icon` |
| `filterPanelIconActive` | `--revo-grid-filter-panel-icon-active` |
| `filterPanelSelectArrow` | `--revo-grid-filter-panel-select-arrow` |
| `filterPanelSelectArrowDisabled` | `--revo-grid-filter-panel-select-arrow-disabled` |
### Buttons
| Token | CSS custom property |
| --------------------- | ----------------------------------- |
| `buttonText` | `--revo-grid-button-text` |
| `buttonBg` | `--revo-grid-button-bg` |
| `buttonSuccessBg` | `--revo-grid-button-success-bg` |
| `buttonDangerBg` | `--revo-grid-button-danger-bg` |
| `buttonOutlineBorder` | `--revo-grid-button-outline-border` |
| `buttonOutlineText` | `--revo-grid-button-outline-text` |
Token values are CSS strings. RevoGrid does not inject arbitrary CSS or global stylesheets; use normal selectors when token-level customization is not sufficient.
---
# Real-Time Updates in RevoGrid
Source: https://rv-grid.com/guide/realtime-updates
Description: Learn how to stream live data into RevoGrid while keeping large datasets responsive with virtualization, targeted updates, and batched rendering.
::: info Live update demo
The overview demo below uses the same grid setup pattern, then refreshes stock-like values on an interval. Scroll the grid while the data changes to see how virtualization keeps the visible area responsive.
:::
RevoGrid works well for live dashboards, trading screens, monitoring tools, and operational grids where values change while users keep scrolling, filtering, or editing. The grid is virtualized by default, so frequent updates do not require every row and column to exist in the DOM at the same time.
Start with the same setup from the quick start: define columns, assign a `source`, and let RevoGrid render the visible viewport.
```ts
// Get the grid element from the page
const grid = document.querySelector('revo-grid');
// Define the columns users will see
grid.columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'role', name: 'Role' },
];
// Provide the rows to render
grid.source = [
{ name: 'Ada Lovelace', role: 'Mathematician' },
{ name: 'Grace Hopper', role: 'Scientist' },
];
```
## Update the whole source
Use a full `source` assignment when your application receives a new snapshot, page, filter result, or server response.
```ts
const rows = [
{ id: 1, symbol: 'REV', price: 120.40 },
{ id: 2, symbol: 'GRID', price: 88.10 },
];
grid.columns = [
{ prop: 'symbol', name: 'Symbol' },
{ prop: 'price', name: 'Price' },
];
grid.source = rows;
setInterval(() => {
grid.source = rows.map(row => ({
...row,
price: Number((row.price + (Math.random() - 0.5) * 4).toFixed(2)),
}));
}, 1000);
```
This is the simplest model and is usually enough for modest update rates. It also matches state-driven frameworks where the grid receives a fresh array after your store changes.
## Update one cell
For frequent single-cell changes, use `setDataAt` so the grid can update a specific cell instead of replacing the full source.
```ts
await grid.setDataAt({
row: 0,
col: 1,
val: 123.45,
});
```
Use this pattern for live prices, status indicators, counters, progress values, and telemetry cells where the row and column are already known.
## Batch fast streams
If updates arrive faster than the browser should paint, collect them and flush once per animation frame.
```ts
const pending = new Map();
let scheduled = false;
function queuePrice(rowIndex: number, price: number) {
pending.set(String(rowIndex), price);
if (scheduled) return;
scheduled = true;
requestAnimationFrame(async () => {
scheduled = false;
for (const [rowIndex, price] of pending) {
await grid.setDataAt({
row: Number(rowIndex),
col: 1,
val: price,
});
}
pending.clear();
});
}
```
Batching keeps high-frequency streams from fighting the browser render loop. It also gives your application a clear place to drop stale updates if newer values arrive for the same row.
## Keep virtualization enabled
Real-time grids usually need virtualization more than static grids. Leave virtual rendering enabled for large row or column counts, and tune only when you understand the tradeoff.
- Keep `disableVirtualY` off for large datasets.
- Keep `disableVirtualX` off for wide grids.
- Increase `frameSize` only if very fast scrolling shows blanking around the viewport.
- Keep cell templates cheap because they may run many times while users scroll.
See [Performance and Virtualization](https://rv-grid.com/guide/performance) for the detailed performance settings.
## Recommended update strategy
Choose the update shape based on the incoming data:
| Stream shape | Recommended approach |
| --- | --- |
| Complete server snapshot | Assign `grid.source` with the new rows |
| Small number of known cells | Use `setDataAt` |
| Bursty WebSocket messages | Queue updates and flush with `requestAnimationFrame` |
| Server-side paging or filtering | Replace the current source page |
| User edits plus live updates | Keep an application data store and reconcile edits before assigning source |
## Practical checklist
- Assign `columns` once unless the schema actually changes.
- Preserve row identity in your application store with stable IDs.
- Batch rapid updates before touching the grid.
- Avoid expensive custom cell templates for values that change often.
- Use [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control) for targeted methods such as `setDataAt`.
- Use [Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync) when your app needs a clear source-of-truth strategy.
---
# TypeScript Data Grid
Source: https://rv-grid.com/guide/ts
Description: Use RevoGrid as a TypeScript data grid with typed row models, reusable column definitions, public instance methods, and framework-agnostic APIs.
RevoGrid is built in TypeScript and exposes typed APIs for columns, events, methods, plugins, and framework wrappers. If your app is already using TypeScript, you can treat the grid as a typed UI boundary rather than a loosely typed widget.
## What TypeScript gives you in RevoGrid
- typed row models for `source`
- typed column configuration with reusable `columnTypes`
- typed event payloads for editing, filtering, focus, and source updates
- typed instance methods such as `setDataAt`, `getVisibleSource`, and `getSelectedRange`
## Minimal typed setup
```ts
interface PersonRow {
id: number;
name: string;
email: string;
}
const grid = document.querySelector('revo-grid');
const columns = [
{ prop: 'id', name: 'ID', readonly: true },
{ prop: 'name', name: 'Name' },
{ prop: 'email', name: 'Email' },
];
const source: PersonRow[] = [
{ id: 1, name: 'Ada Lovelace', email: 'ada@example.com' },
{ id: 2, name: 'Grace Hopper', email: 'grace@example.com' },
];
grid!.columns = columns;
grid!.source = source;
```
## Good TypeScript patterns
- define a dedicated row interface for each grid
- keep `prop` values aligned with actual row keys
- extract shared `columnTypes` for repeated formatting and editor rules
- type your event handlers when you need to inspect `detail`
## Where to go next
- [Advanced Types](https://rv-grid.com/guide/types/README)
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [API Reference](https://rv-grid.com/guide/api/revoGrid)
---
# Angular Data Grid
Source: https://rv-grid.com/guide/angular
Description: Learn how to use RevoGrid in Angular with standalone components or modules, pass columns and source data, and access the underlying grid API.
RevoGrid shines in Angular when you want a high-performance grid without giving up framework-native templates and editors. The Angular wrapper keeps the grid convenient to use while still exposing the same core RevoGrid API.
::: info
This tutorial assumes that an Angular project already exists. If not, start with the official [Angular installation guide](https://angular.dev/installation).
:::
## Install your Angular Data Grid
Install [RevoGrid for Angular](https://github.com/revolist/angular-datagrid) using the following command:
::: code-group
```npm
npm i @revolist/angular-datagrid
```
```pnpm
pnpm add @revolist/angular-datagrid
```
```yarn
yarn add @revolist/angular-datagrid
```
```bun
bun add @revolist/angular-datagrid
```
:::
## Standalone component setup
```ts
import { Component } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
@Component({
selector: 'app-root',
standalone: true,
imports: [RevoGrid],
template: ``,
})
export class AppComponent {
source = [
{ name: 'Item 1', details: 'First row' },
{ name: 'Item 2', details: 'Second row' },
];
columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'details', name: 'Details' },
];
}
```
## Module-based setup
If your Angular app still uses modules, RevoGrid can be imported there as well:
::: code-group
```ts [app.module.ts]
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RevoGrid } from '@revolist/angular-datagrid';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, RevoGrid],
bootstrap: [AppComponent],
})
export class AppModule {}
```
```ts [app.component.ts]
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: ``,
})
export class AppComponent {
source = [
{ name: 'Item 1', details: 'First row' },
{ name: 'Item 2', details: 'Second row' },
];
columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'details', name: 'Details' },
];
}
```
:::
::: warning Dynamic Component Usage
When using RevoGrid with Angular 19+, there are known edge cases with dynamically loading or using the component in certain scenarios. The grid frame may render, but columns and source data may not display properly.
**Known Symptoms:**
- Columns and source data might not render when the component is used dynamically.
- Plugins and readonly properties may stop working in some dynamic scenarios.
- Silent errors might occur without any visible error messages.
**Related GitHub Discussion:** [GitHub Discussion #798](https://github.com/revolist/revogrid/issues/798)
**Helpful Resources:**
- [Angular Component Communication](https://angular.dev/guide/components/inputs-outputs)
- [Angular Standalone Components](https://angular.dev/guide/components/importing)
- [Angular Router Outlet](https://angular.dev/api/router/RouterOutlet)
If you encounter issues with dynamic component usage, please report them on [GitHub Issues](https://github.com/revolist/revogrid/issues) with details about your Angular version and setup.
:::
## Accessing grid instance methods
When you need to call public methods such as `scrollToRow`, `setCellEdit`, or `getVisibleSource`, grab the underlying element and call the API on that instance.
## Custom renderers and editors
Use these Angular-specific guides for deeper integration:
- [Angular Cell Template](https://rv-grid.com/guide/angular/renderer)
- [Angular Cell Editor](https://rv-grid.com/guide/angular/editor)
## Event handling
Angular applications typically listen to the same RevoGrid lifecycle events as other integrations:
- `beforeedit`
- `afteredit`
- `beforefilterapply`
- `beforesourceset`
## Related guides
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
## Check out our Angular Data Grid examples
---
# Angular Data Grid Cell Template
Source: https://rv-grid.com/guide/angular/renderer
Description: Cell template rendering in Angular Data Grid, enabling custom Angular components inside grid cells.
RevoGrid provide a way to render native components inside of cells.
::: warning
If you are aiming for the faster render we are recommending to stick with native VNode render.
:::
::: tip
Check [ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel) for mode information about input types.
:::
[](https://codesandbox.io/p/sandbox/rg-cell-angular-standalone-t4lrz2)
## Why Use Custom Cell Rendering?
RevoGrid’s native cell rendering enables you to:
- **Embed Components**: Render complex or interactive UI elements inside grid cells, such as buttons, images, input fields, or custom widgets.
- **Dynamic Content**: Customize each cell’s content based on the data it represents, such as formatting or conditional rendering.
- **Interactivity**: Make cells interactive with event listeners and component lifecycle methods, improving the overall user experience.
## Cell Component
First, let's create a component to be displayed as a cell. This component will receive the cell's properties as an input and display it.
```ts
// cell.component.ts
import { Component, Input } from '@angular/core';
import { ColumnDataSchemaModel } from '@revolist/revogrid';
@Component({
selector: 'app-cell',
standalone: true,
template: ' {{value}} works!',
})
export class CellComponent {
@Input() props!: ColumnDataSchemaModel;
get value() {
return this.props.rowIndex;
}
}
```
## Grid Component and Cell Template
Next let's create a component that will be used to render the grid. This component will receive the grid's properties as an input and display it. At the same time, it will set the cell's template as native element of the cell.
```ts
// app.component.ts
import { Component } from "@angular/core";
import { RevoGrid, Template } from "@revolist/angular-datagrid";
import { CellComponent } from "./cell.component";
@Component({
selector: "app-root",
standalone: true,
imports: [RevoGrid, CellComponent],
template: ``,
})
export class AppComponent {
source = [
{
name: "1",
details: "Item 1",
},
{
name: "2",
details: "Item 2",
},
];
columns = [
{
prop: "name",
name: "First",
cellTemplate: Template(CellComponent),
},
{
prop: "details",
name: "Second",
},
];
}
```
## Check out our Angular Data Grid examples
---
# Angular Data Grid Editor
Source: https://rv-grid.com/guide/angular/editor
Description: Learn how to implement editor in Data Grid with Angular, enabling custom in-cell editing using Angular components.
RevoGrid provides a way to render native components as editor.
::: tip
You can access close and save callbacks in properties. Check [editor](https://rv-grid.com/guide/cell/editor) and `EditorCtr` type for more.
:::
# Native Editor Component Demo
[](https://codesandbox.io/p/sandbox/rg-editor-angular-standalone-lgc3pr)
## Editor as standalone component
First we need to create a custom editor component.
```ts
// editor.component.ts
import { Component, Input } from "@angular/core";
import { type EditorType } from "@revolist/angular-datagrid";
@Component({
selector: "app-editor",
standalone: true,
template: '',
})
export class EditorComponent {
@Input() props!: EditorType;
testClick() {
this.props.close();
}
}
```
## Grid Component and Editor
Next, let's create standalone component that will be used to render the grid.
Now we can render the grid with the custom editor component.
```ts
// app.component.ts
import { Component } from "@angular/core";
import {
RevoGrid,
Editor,
type Editors,
type ColumnRegular,
} from "@revolist/angular-datagrid";
import { EditorComponent } from "./editor.component";
const MY_EDITOR = "custom-editor";
@Component({
selector: "app-root",
standalone: true,
imports: [RevoGrid, EditorComponent],
template: ``,
})
export class AppComponent {
source = [
{
name: "1",
details: "Item 1",
},
{
name: "2",
details: "Item 2",
},
];
columns: ColumnRegular[] = [
{
prop: "name",
name: "First",
// define editor
editor: MY_EDITOR,
},
{
prop: "details",
name: "Second",
},
];
// provide editor classes
editors: Editors = { [MY_EDITOR]: Editor(EditorComponent) };
}
```
## Check out our Angular Data Grid examples
---
# Angular Tree Data Grid
Source: https://rv-grid.com/guide/angular/tree
Description: Build an Angular tree data grid with the free RevoGrid core tree pattern, then upgrade to RevoGrid Pro TreeDataPlugin for expandable hierarchy controls, sticky parents, and drag-and-drop.
Angular applications can start with the free/core tree pattern by preparing a flat `source` array in the component and rendering indentation through a cell template.
::: info
The core tree pattern does not require Pro plugins. The current live `core-tree` widget is published for TypeScript, React, and Vue; Angular uses the same flattened `source` and cell-template approach.
:::
Tree-like rows do not require Pro when your application only needs a visual hierarchy. The free/core approach is to flatten parent-child records into display order, add a `level` field, and render indentation in a cell template.
This keeps RevoGrid simple: the grid receives a normal `source` array, virtualization still works, and your application owns the hierarchy transformation.
## Tree model
Start with records that have an ID and a parent ID:
```ts
const inputData = [
{ id: 4, parentId: 0, name: 'Antoni father for 2' },
{ id: 5, parentId: 4, name: 'Odin' },
{ id: 6, parentId: 4, name: 'John' },
{ id: 1, parentId: 0, name: 'Mary mother for 2' },
{ id: 2, parentId: 1, name: 'Howard has also 2' },
];
```
Convert that data into a flat display list before assigning it to the grid:
```ts
function buildTreeData(rows: typeof inputData, rootParentId = 0) {
const childrenByParent = new Map();
for (const row of rows) {
const children = childrenByParent.get(row.parentId) ?? [];
children.push(row);
childrenByParent.set(row.parentId, children);
}
const result: Array<(typeof inputData)[number] & { level: number }> = [];
function appendChildren(parentId: number, level = 0) {
for (const child of childrenByParent.get(parentId) ?? []) {
result.push({ ...child, level });
appendChildren(child.id, level + 1);
}
}
appendChildren(rootParentId);
return result;
}
```
## Indented cell template
The core demo uses a normal cell template to show hierarchy depth:
```ts
const columns = [
{
prop: 'name',
name: 'Tree',
size: 300,
cellTemplate(h, { value, model }) {
return h(
'div',
{
style: {
marginLeft: `${(model?.level ?? 0) * 30}px`,
},
},
value || '',
);
},
},
{
prop: 'level',
readonly: true,
},
];
```
Use the core approach when the hierarchy is read-only or mostly decorative: category outlines, simple nested lists, document sections, or a tree table where your app handles all expand/collapse logic outside the grid.
## Core limits
The free/core pattern is intentionally lightweight. It does not add built-in expand/collapse controls, automatic parent-child visibility, tree-aware drag-and-drop, sticky parent rows, or parent/descendant row selection behavior. Those behaviors belong in the Pro Tree Data plugin.
## Angular notes
- Build `source` from your component, service, signal, or store.
- Bind `[columns]` and `[source]` normally; no Pro plugin is needed for the core tree.
- Keep the tree transformation separate from the component template.
```ts
```
## Pro Tree Data
RevoGrid Pro adds a dedicated `TreeDataPlugin` for advanced data grid tree structures. It keeps the original `source` flat, computes hierarchy metadata internally, and renders tree controls in the column marked with `tree: true`.
::: info RevoGrid Pro
Use the Pro plugin when hierarchy is not just indentation: users need expand/collapse controls, persistent expansion state, filtering and sorting with hierarchy awareness, row selection across descendants, drag-and-drop reparenting, or sticky parent rows while scrolling long branches.
:::
### Pro data model
The Pro model also starts from stable IDs and parent IDs:
```ts
type TeamRow = {
id: string;
parentId: string | null;
name: string;
role: string;
budget: number;
};
const source: TeamRow[] = [
{ id: 'eng', parentId: null, name: 'Engineering', role: 'Department', budget: 850000 },
{ id: 'platform', parentId: 'eng', name: 'Platform', role: 'Team', budget: 320000 },
{ id: 'api', parentId: 'platform', name: 'API', role: 'Squad', budget: 140000 },
{ id: 'design', parentId: null, name: 'Design', role: 'Department', budget: 260000 },
];
```
Unlike the core example, you do not add `level` yourself. The plugin derives level, visibility, expanded state, and child metadata from the tree config.
### Pro column and plugins
Mark one hierarchy column with `tree: true`, register `TreeDataPlugin`, and pass the `tree` config:
```ts
import {
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
TREE_EXPAND_ALL_EVENT,
TREE_COLLAPSE_ALL_EVENT,
} from '@revolist/revogrid-pro';
const columns = [
{
prop: 'name',
name: 'Team',
size: 300,
tree: true,
sortable: true,
rowSelect: true,
rowDrag: true,
},
{ prop: 'role', name: 'Role', size: 160 },
{ prop: 'budget', name: 'Budget', size: 140 },
];
const plugins = [
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
];
const tree = {
idField: 'id',
parentIdField: 'parentId',
rootParentId: null,
expandedRowIds: new Set(['eng']),
stickyParents: true,
};
```
Framework wrappers pass these values as props or bindings. Plain TypeScript assigns them to the `revo-grid` element.
### Expand and collapse controls
The Pro plugin exposes events for toolbar buttons and external controls:
```ts
grid.dispatchEvent(new CustomEvent(TREE_EXPAND_ALL_EVENT));
grid.dispatchEvent(new CustomEvent(TREE_COLLAPSE_ALL_EVENT));
```
Use `expandAll: true` when every branch should open on first render. Use `expandedRowIds` when you want controlled initial state or persisted expansion.
### Production guidance
- Keep IDs stable across refreshes so expanded state survives data updates.
- Use `parentId: null` or another explicit `rootParentId` consistently.
- Keep only one tree column active; use normal columns for the rest of the row data.
- Combine tree data with virtualization for large hierarchies instead of rendering nested DOM lists.
- Add `StickyCellsPlugin` only when sticky parent rows are useful for long branches.
- Reconcile drag-and-drop changes in your application store before saving to the backend.
- Prefer flat server payloads for large trees; they are simpler to page, diff, validate, and persist.
## Related guides
- [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data)
- [Row Ordering](https://rv-grid.com/guide/row/order)
- [Row Selection](https://rv-grid.com/guide/row/selection.pro)
- [Filtering](https://rv-grid.com/guide/filters)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
---
# React Data Grid
Source: https://rv-grid.com/guide/react
Description: Learn how to use RevoGrid in React with typed props, refs to the underlying grid instance, custom renderers, custom editors, and event handling.
RevoGrid gives React applications a fast virtualized data grid without changing the core grid behavior. You pass `columns` and `source` as props, then use a ref when you need to call instance methods such as `setCellEdit`, `scrollToRow`, or `getVisibleSource`.
## Install your React Data Grid
Install [RevoGrid for React](https://github.com/revolist/react-datagrid) using the following command:
::: code-group
```npm
npm i @revolist/react-datagrid
```
```pnpm
pnpm add @revolist/react-datagrid
```
```yarn
yarn add @revolist/react-datagrid
```
```bun
bun add @revolist/react-datagrid
```
:::
## Minimal setup
```tsx
// App.tsx
import { RevoGrid } from '@revolist/react-datagrid'
import { useState } from 'react'
/**
* note: columns & source need a "stable" reference in order to prevent infinite re-renders
*/
const columns = [
{
prop: 'name',
name: 'First',
},
{
prop: 'details',
name: 'Second',
},
]
function App() {
const [source] = useState([
{
name: '1',
details: 'Item 1',
},
{
name: '2',
details: 'Item 2',
},
])
return (
<>
>
)
}
export default App
```
# React Data Grid Demo
Use this React demo to start a RevoGrid table with virtualized rows and columns, editable cells, and high-performance rendering for large datasets.
[](https://codesandbox.io/p/sandbox/react-revogrid-start-29fm5z)
## Working with `columns` and `source`
In React, the most maintainable pattern is:
- keep `columns` stable unless configuration really changed
- update `source` from application state
- use grid methods for imperative actions instead of reaching into internal DOM
## Accessing grid instance methods
Use a ref to the wrapped grid element, then call the public API on the underlying instance:
```tsx
import { useRef } from 'react';
function App() {
const gridRef = useRef(null);
const focusFirstPriceCell = async () => {
await gridRef.current?.scrollToRow?.(0);
await gridRef.current?.setCellEdit?.(0, 'price');
};
return (
<>
>
);
}
```
## Custom renderers and editors
Use these pages for React-specific customization:
- [React Cell Template](https://rv-grid.com/guide/react/renderer)
- [React Cell Editor](https://rv-grid.com/guide/react/editor)
## Event handling
React apps usually listen for the same grid events as plain JavaScript:
- `beforeedit`
- `afteredit`
- `beforefilterapply`
- `beforesourceset`
If you need to shape event-driven workflows, start with [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide).
## SSR and client-only behavior
RevoGrid depends on browser APIs, so server-rendered React environments should load it on the client side. If your app uses Next.js or another SSR framework, render the grid in a client component or dynamically load it on the client.
## Related guides
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
## Check out our React Data Grid examples
---
# React Data Grid Cell Template Support
Source: https://rv-grid.com/guide/react/renderer
Description: React cell template support in RevoGrid for React, allowing the use of custom React components inside grid cells.
# React Data Grid Cell Template
RevoGrid provide a way to render native components inside of cells.
::: warning
If you are aiming for the faster render we are recommending to stick with native VNode render.
:::
::: tip
Check [ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel) for mode information about input types.
:::
This capability, known as native cell rendering, allows developers to customize how the grid cells are displayed, providing a high degree of control over their appearance and behavior.
# React Custom Cell Template Demo
[](https://codesandbox.io/p/sandbox/react-revogrid-cell-jgt3mv)
### Key Considerations for Custom Cell Templates
- **Data Access**: Each custom cell component will have access to the data for that row via its props. The primary prop that is passed to custom renderers is the value of the cell.
- **Performance**: Custom renderers can impact grid performance, especially with large datasets. RevoGrid optimizes rendering by only updating cells that have changed, but it’s important to keep performance in mind when creating complex cell templates.
- **Conditional Rendering**: You can use conditional logic inside your custom cell component to change its appearance based on the data. For example, you can display different colors or icons based on numeric values or boolean flags.
- **Event Handling**: Custom cells can include event handlers, such as onClick, onChange, etc., to make the grid interactive. This is ideal for rendering editable fields, buttons, or custom controls.
### Advanced Use Cases
RevoGrid’s native rendering support opens up even more complex scenarios where you can render interactive components, such as:
- **Dynamic Dropdowns**: Populate a dropdown inside a cell based on the data in the grid or external sources.
- **Custom Formatting**: Display values with custom formatting, such as currency symbols, percentages, or styled numbers.
- **Inline Editing**: Build advanced inline editing components, such as date pickers, checkboxes, or toggles, inside grid cells.
In this guide, we will explore how to implement custom cell renderers and templates within your RevoGrid in React. Whether you need to render custom React components, include dynamic data, or create interactive cell behaviors, RevoGrid’s native rendering support ensures that your cells are more than just plain text.
## Why Use Custom Cell Rendering?
RevoGrid’s native cell rendering enables you to:
- **Embed Components**: Render complex or interactive UI elements inside grid cells, such as buttons, images, input fields, or custom widgets.
- **Dynamic Content**: Customize each cell’s content based on the data it represents, such as formatting or conditional rendering.
- **Interactivity**: Make cells interactive with event listeners and component lifecycle methods, improving the overall user experience.
## Basic Setup
Here’s an example of how you can use a simple React component to render custom content inside a grid cell.
```tsx{10-12,21}
// App.tsx
import { type ColumnDataSchemaModel, RevoGrid, Template } from '@revolist/react-datagrid';
import { useState } from 'react'
/**
* Custom cell component
*/
const Cell = ({ value }: Partial) => {
return
{value}
;
};
/**
* note: columns & source need a "stable" reference in order to prevent infinite re-renders
*/
const columns = [
{
prop: 'name',
name: 'First',
cellTemplate: Template(Cell),
},
];
function App() {
const [source] = useState([
{
name: '1',
details: 'Item 1',
},
]);
return (
<>
>
)
}
export default App;
```
In the example above:
- We define a `Cell` component that accepts a value prop and renders it inside a `span` element with custom styles.
- The columns definition includes the `cellTemplate` property, which references the `Cell` component.
- RevoGrid automatically uses `Cell` to render the name column.
## Check out our React Data Grid examples
---
# React Data Grid Editor
Source: https://rv-grid.com/guide/react/editor
Description: Learn how to implement editor in Data Grid with React, enabling custom in-cell editing using React components.
RevoGrid provides a way to render native components as editor.
::: tip
You can access close and save callbacks in properties. Check [editor](https://rv-grid.com/guide/cell/editor) and `EditorCtr` type for more.
:::
By integrating React components as native editors, RevoGrid gives you full control over how each cell behaves during the editing process, enabling complex and highly interactive editing scenarios.
# React Data Grid Cell Editor Demo
RevoGrid allows for even more complex custom editors by passing data and handling events like onChange or onBlur. You can create more interactive editors such as input fields, checkboxes, or dropdowns that allow users to update cell values directly.
[](https://codesandbox.io/p/sandbox/react-revogrid-cell-vdjyp2)
### Advanced Use Cases
You can extend RevoGrid’s native editor rendering by implementing more sophisticated editors, such as:
- **Date Pickers**: Use a date picker React component to edit date values in a column.
- **Select Menus**: Render a dropdown menu with dynamic options based on other grid data or external sources.
- **Multistep Editors**: Create complex multi-field editors for advanced data entry.
## Why Use Custom Editors?
With native editor rendering, you can:
- **Customize the Editing Experience**: Use any React component as a custom editor, providing a tailored user interface for editing data directly in the grid.
- **Build Complex Editors**: Embed interactive elements such as date pickers, dropdowns, or custom forms inside cells, which would be impossible with simple input fields alone.
- **Improve Usability**: Create inline editors that match your application’s UI, improving consistency and enhancing the overall user experience.
## Basic Setup
RevoGrid allows you to define custom editors for grid cells using the editor property on columns. You can then assign React components to handle the rendering and editing of cell values.
In this example, we’ll create a custom button editor that, when clicked, closes the editor. This demonstrates how you can use React components as editors.
```tsx{4,10-12,22,34}
// App.tsx
import { RevoGrid, Editor, type EditorType, type Editors } from '@revolist/react-datagrid';
import { useState } from 'react'
/**
* Custom editor component
*/
const Button = ({ close }: EditorType) => {
return
};
const MY_EDITOR = 'custom-editor';
/**
* note: columns & source need a "stable" reference in order to prevent infinite re-renders
*/
const columns = [
{
prop: 'name',
name: 'First',
editor: MY_EDITOR,
},
];
function App() {
const [source] = useState([
{
name: '1',
details: 'Item 1',
},
]);
const gridEditors: Editors = { [MY_EDITOR]: Editor(Button) };
return (
<>
>
)
}
export default App;
```
### Key Components
- **Custom Editor**: The Button component is a simple React component that will be used as a custom editor for the “First” column. When clicked, it will close the editor.
- **Editor Registration**: The gridEditors object registers the custom editor using the Editor function. In this case, it links the custom editor (the Button component) to the identifier MY_EDITOR.
- **Editor Prop**: In the columns array, the editor property is set to MY_EDITOR, indicating that the custom editor should be used for the “First” column.
## Check out our React Data Grid examples
---
# Dash Data Grid
Source: https://rv-grid.com/guide/dash
Description: Install and use RevoGrid Core in Plotly Dash with typed Python props, DataFrame records, editing, sorting, filtering, and JSON-safe callbacks.
[`dash-datagrid`](https://github.com/revolist/dash-datagrid) is the official RevoGrid Core integration for
[Plotly Dash](https://dash.plotly.com/). It exposes the grid as the generated
Python component `dash_datagrid.RevoGrid` and packages the required JavaScript
with the Python distribution.
Use this integration when the application layout and callbacks are written in
Python, while the virtualized grid runs in the browser.
## Guides
- [Getting Started](https://rv-grid.com/guide/dash/getting-started) — install the package and run your first grid.
- [DataFrames](https://rv-grid.com/guide/dash/dataframes) — load JSON-safe rows and pandas DataFrames.
- [Columns](https://rv-grid.com/guide/dash/columns) — configure columns and common grid features.
- [Callbacks and Events](https://rv-grid.com/guide/dash/callbacks-and-events) — receive grid events in Dash callbacks.
- [Edit Synchronization](https://rv-grid.com/guide/dash/edit-synchronization) — choose compact edit deltas or complete source synchronization.
- [Property Reference](https://rv-grid.com/guide/dash/property-reference) — review supported properties and Python boundary limitations.
- [Core API Reference](https://rv-grid.com/guide/dash/core-api-reference) — find the complete RevoGrid API documentation.
## Packages and compatibility
| Distribution | Name | Purpose |
| --- | --- | --- |
| PyPI | [`dash-datagrid`](https://github.com/revolist/dash-datagrid) | Normal installation for a Dash application |
| Python import | `dash_datagrid` | Exports `RevoGrid` |
| npm | [`@revolist/dash-datagrid`](https://github.com/revolist/dash-datagrid) | JavaScript distribution used by the generated Dash component |
The Python package supports Python 3.10 or newer and Dash 3.x or 4.x. A normal
Python application only installs [`dash-datagrid`](https://github.com/revolist/dash-datagrid); Dash serves the packaged
JavaScript locally, so a separate npm install is not required.
Version 1 covers RevoGrid Core. Pro and Enterprise plugin activation, custom
JavaScript renderers or editors, imperative methods, and synchronous
client-side cancellation are not exposed through the Python component.
---
# Dash Getting Started
Source: https://rv-grid.com/guide/dash/getting-started
Description: Install Dash DataGrid and run your first RevoGrid application in Plotly Dash.
## Packages and compatibility
| Distribution | Name | Purpose |
| --- | --- | --- |
| [PyPI](https://pypi.org/project/dash-datagrid/) | [`dash-datagrid`](https://github.com/revolist/dash-datagrid) | Python package for a normal Dash application |
| Python import | `dash_datagrid` | Exports `RevoGrid` |
| [npm](https://www.npmjs.com/package/@revolist/dash-datagrid) | [`@revolist/dash-datagrid`](https://github.com/revolist/dash-datagrid) | Generated React bridge and bundled RevoGrid custom element |
The Python package supports Python 3.10 or newer and Dash 3.x or 4.x. A normal
Python application only installs [`dash-datagrid`](https://github.com/revolist/dash-datagrid); Dash serves the packaged
JavaScript locally, so a separate npm install is not required.
The current distributions cover RevoGrid Core. Pro and Enterprise plugin activation, custom
JavaScript renderers or editors, imperative methods, and synchronous
client-side cancellation are not exposed through the Python component.
## Build your first grid
### 1. Create an environment
```bash
python -m venv .venv
source .venv/bin/activate
```
On Windows PowerShell, activate it with:
```powershell
.venv\Scripts\Activate.ps1
```
### 2. Install Dash DataGrid with Python
```bash
python -m pip install dash-datagrid
```
This installs the official
[`dash-datagrid` package from PyPI](https://pypi.org/project/dash-datagrid/)
and its compatible Dash dependency automatically. To use the DataFrame
examples, install pandas too:
```bash
python -m pip install pandas
```
### npm installation
Use the npm distribution only when consuming or extending the generated
React/JavaScript bridge directly. A standard Python Dash application does not
need this step.
```bash
npm install @revolist/dash-datagrid
```
The npm package requires Node.js 22 or newer. React and ReactDOM 18.3.1 or newer
within the React 18 release line are peer dependencies:
```bash
npm install react@^18.3.1 react-dom@^18.3.1
```
### 3. Create `app.py`
```python
from dash import Dash, Input, Output, callback, html
from dash_datagrid import RevoGrid
app = Dash(__name__)
app.layout = html.Main(
[
html.H1("Orders"),
RevoGrid(
id="orders-grid",
columns=[
{
"prop": "order",
"name": "Order",
"readonly": True,
"size": 130,
},
{
"prop": "customer",
"name": "Customer",
"sortable": True,
"size": 180,
},
{
"prop": "amount",
"name": "Amount",
"sortable": True,
"filter": "number",
},
],
source=[
{"order": "A-100", "customer": "Ada", "amount": 120},
{"order": "A-101", "customer": "Grace", "amount": 85},
{"order": "A-102", "customer": "Linus", "amount": 210},
],
rowHeaders=True,
resize=True,
range=True,
filter=True,
style={"height": 420},
),
html.Pre("Edit a cell to see its event.", id="edit-output"),
]
)
@callback(
Output("edit-output", "children"),
Input("orders-grid", "afteredit"),
prevent_initial_call=True,
)
def show_edit(event):
detail = event["detail"]
if "prop" not in detail:
return f"Range edit: {detail}"
return (
f'Row {detail["rowIndex"]}, {detail["prop"]} '
f'changed to {detail["val"]!r}'
)
if __name__ == "__main__":
app.run(debug=True)
```
Every column `prop` maps to a key in each source row. Set an explicit component
height in `style`; the grid fills its Dash host, and the host needs a usable
height.
### 4. Run the application
```bash
python app.py
```
Open the local address printed by Dash, normally `http://127.0.0.1:8050`.
### Complete example project
The
[`examples/` project](https://github.com/revolist/dash-datagrid/tree/main/examples)
includes a dependency manifest, DataFrame normalization, responsive styling,
Python-driven source changes, dedicated callbacks, and generic event
listeners.
```bash
git clone https://github.com/revolist/dash-datagrid.git
cd dash-datagrid/examples
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python app.py
```
---
# Dash DataFrames
Source: https://rv-grid.com/guide/dash/dataframes
Description: Load JSON-safe rows and pandas DataFrames into RevoGrid for Plotly Dash.
## Source rows
`source`, `pinnedTopSource`, and `pinnedBottomSource` accept lists of
JSON-serializable row objects:
```python
rows = [
{"id": 1, "product": "Keyboard", "price": 95.0},
{"id": 2, "product": "Mouse", "price": 35.5},
]
```
Values that cross the Dash boundary should be strings, finite numbers,
booleans, `None`, lists, or dictionaries containing those values. Convert
`datetime`, `Decimal`, NumPy scalar, UUID, and other Python-specific values
before assigning a prop.
See [Data & Rows](https://rv-grid.com/guide/row) for the Core row model and
[Data Source Loading and Syncing](https://rv-grid.com/guide/data-sync) for source ownership
patterns.
## pandas DataFrames
For a DataFrame containing only JSON-native values, records are enough:
```python
rows = frame.to_dict("records")
grid = RevoGrid(columns=columns, source=rows, style={"height": 420})
```
For dates, missing values, NumPy values, or other pandas-specific types, use a
JSON round trip to normalize the records:
```python
import json
rows = json.loads(
frame.to_json(
orient="records",
date_format="iso",
)
)
```
This converts timestamps to ISO strings and missing values to JSON `null`,
which arrives in Python callbacks as `None`.
## Python-driven updates
Return a new `source` when the application intentionally loads a different
dataset:
```python
from dash import Input, Output, callback
@callback(
Output("orders-grid", "source"),
Input("reload-orders", "n_clicks"),
prevent_initial_call=True,
)
def reload_orders(_clicks):
return load_orders_from_database()
```
Full source replacement is appropriate for reloads, searches, pagination, or
dataset changes. For a normal cell edit, prefer the compact `afteredit` event
described in [Edit synchronization](https://rv-grid.com/guide/dash/edit-synchronization).
---
# Dash Columns
Source: https://rv-grid.com/guide/dash/columns
Description: Configure RevoGrid columns and common grid features in Plotly Dash.
# Columns
A column is a plain dictionary. `prop` is required and selects the value from
each source row.
```python
columns = [
{
"prop": "id",
"name": "ID",
"readonly": True,
"pin": "colPinStart",
"size": 90,
},
{
"prop": "customer",
"name": "Customer",
"sortable": True,
"minSize": 140,
},
{
"prop": "amount",
"name": "Amount",
"sortable": True,
"filter": "number",
"order": "desc",
},
]
```
Common JSON-safe column fields are:
| Field | Purpose |
| --- | --- |
| `prop` | Row key used by the column |
| `name` | Header label |
| `size`, `minSize`, `maxSize` | Width constraints in pixels |
| `readonly` | Disable editing for the column |
| `sortable`, `order` | Enable sorting and set `asc` or `desc` order |
| `filter` | Enable a string, number, or other built-in filter family |
| `pin` | Use `colPinStart` or `colPinEnd` |
| `rowDrag` | Add a row-drag handle |
| `columnType` | Apply a preset from the grid-level `columnTypes` prop |
Function-valued column members are not supported in v1. This includes
`cellTemplate`, `columnTemplate`, `cellProperties`, `columnProperties`,
`cellCompare`, `cellParser`, constructor-based `editor` values, function-based
`readonly`, and function-based `rowDrag`.
Use the [Column Configuration guide](https://rv-grid.com/guide/column), the complete
[`ColumnRegular` interface](https://rv-grid.com/guide/types/Interface.ColumnRegular), and the
[`ColumnGrouping` interface](https://rv-grid.com/guide/types/Interface.ColumnGrouping) to inspect
the Core schema. When reading those pages, remember that Dash can use only
primitive and plain-object members.
### Column groups
Nested header groups are plain objects and therefore work across the Dash
boundary:
```python
columns = [
{
"name": "Customer",
"children": [
{"prop": "first_name", "name": "First name"},
{"prop": "last_name", "name": "Last name"},
],
},
{
"name": "Order",
"children": [
{"prop": "status", "name": "Status"},
{"prop": "amount", "name": "Amount", "filter": "number"},
],
},
]
```
See [Column Grouping](https://rv-grid.com/guide/column/grouping).
### Reusable column types
`columnTypes` can hold JSON-safe presets:
```python
RevoGrid(
columnTypes={
"identifier": {"readonly": True, "size": 120},
"money": {"size": 140, "sortable": True, "filter": "number"},
},
columns=[
{"prop": "id", "name": "ID", "columnType": "identifier"},
{"prop": "amount", "name": "Amount", "columnType": "money"},
],
source=rows,
style={"height": 420},
)
```
See [Column Types and Formats](https://rv-grid.com/guide/column/types) and
[Advanced Configuration](https://rv-grid.com/guide/advanced-configuration#columntypes).
## Common feature recipes
### Editing, range selection, and clipboard
```python
RevoGrid(
source=rows,
columns=columns,
readonly=False,
range=True,
useClipboard={"rangeFill": True},
applyOnClose=True,
style={"height": 420},
)
```
- `readonly=True` makes the complete grid read-only.
- A column-level `readonly=True` locks only that column.
- `range=True` enables multi-cell selection.
- `useClipboard=True` enables the built-in copy/paste behavior.
- `rangeFill` requires range selection.
References: [Editing](https://rv-grid.com/guide/editing), [Clipboard](https://rv-grid.com/guide/clipboard),
[`ClipboardConfig`](https://rv-grid.com/guide/types/Interface.ClipboardConfig), and
[Selection API](https://rv-grid.com/guide/api/selectionFocus).
### Filtering and sorting
Enable the filter plugin at grid level, then opt columns into a filter family:
```python
RevoGrid(
filter={
"collection": {
"status": {"type": "eq", "value": "Open"},
}
},
sorting={
"columns": [
{"prop": "amount", "order": "desc"},
],
"additive": False,
},
columns=[
{"prop": "status", "name": "Status", "filter": "string"},
{
"prop": "amount",
"name": "Amount",
"filter": "number",
"sortable": True,
},
],
source=rows,
style={"height": 420},
)
```
Custom filter functions and custom sorting comparators are JavaScript
functions, so they are not supported through Python in v1.
References: [Filtering](https://rv-grid.com/guide/filters),
[`ColumnFilterConfig`](https://rv-grid.com/guide/types/Interface.ColumnFilterConfig),
[Sorting](https://rv-grid.com/guide/sorting), and
[`SortingConfig`](https://rv-grid.com/guide/types/TypeAlias.SortingConfig).
### Row grouping
```python
RevoGrid(
grouping={
"props": ["region", "team"],
"expandedAll": True,
"preserveGroupingOnUpdate": True,
},
columns=columns,
source=rows,
style={"height": 420},
)
```
`groupLabelTemplate` and `getGroupValue` are functions and cannot cross the
Python boundary. The plain-object grouping options work.
References: [Row Grouping](https://rv-grid.com/guide/row/grouping) and
[`GroupingOptions`](https://rv-grid.com/guide/types/TypeAlias.GroupingOptions).
### Sizing, pinned rows, and column movement
```python
RevoGrid(
colSize=120,
rowSize=34,
rowHeaders={"size": 56},
resize=True,
autoSizeColumn=True,
stretch="last",
canMoveColumns=True,
pinnedTopSource=[{"name": "Current selection"}],
pinnedBottomSource=[{"name": "Total"}],
columns=columns,
source=rows,
style={"height": 500},
)
```
References: [Grid Size](https://rv-grid.com/guide/grid.size), [Column Resize](https://rv-grid.com/guide/column/resize),
[Column Autosize](https://rv-grid.com/guide/column/autosize),
[Column Stretch](https://rv-grid.com/guide/column/stretch),
[Column Ordering](https://rv-grid.com/guide/column/order), [Row Headers](https://rv-grid.com/guide/row/headers), and
[Pinned Rows](https://rv-grid.com/guide/row/pin).
### Themes, RTL, accessibility, and virtualization
```python
RevoGrid(
theme="compact",
rtl=False,
accessible=True,
frameSize=1,
disableVirtualX=False,
disableVirtualY=False,
columns=columns,
source=rows,
style={"height": 420},
)
```
Virtual rendering is enabled by default. Leave it enabled for large sources.
`virtualX` can restrict which column dimensions use X-axis virtualization; its
values come from [`DimensionCols`](https://rv-grid.com/guide/types/TypeAlias.DimensionCols).
References: [Themes](https://rv-grid.com/guide/theme), [RTL](https://rv-grid.com/guide/rtl),
[Accessibility](https://rv-grid.com/guide/wcag), [Performance and Virtualization](https://rv-grid.com/guide/performance),
and [Viewports](https://rv-grid.com/guide/viewports).
---
# Dash Callbacks and Events
Source: https://rv-grid.com/guide/dash/callbacks-and-events
Description: Handle RevoGrid events with generated Plotly Dash callback properties.
# Callbacks and events
### Generated callback properties
Every public RevoGrid event discovered in Stencil compiler metadata is generated
as a same-name Dash input property. The most common events are active by
default:
| Dash property | When it updates | Typical `detail` | Core reference |
| --- | --- | --- | --- |
| `afteredit` | A cell or selected range is changed | Compact cell delta, or range data and ranges | [`AfterEditEvent`](https://rv-grid.com/guide/types/TypeAlias.AfterEditEvent) |
| `afterfocus` | Focus rendering completes | Focused cell/range information | [`FocusAfterRenderEvent`](https://rv-grid.com/guide/types/Interface.FocusAfterRenderEvent) |
| `headerclick` | A column header is clicked | JSON-safe column definition | [`ColumnRegular`](https://rv-grid.com/guide/types/Interface.ColumnRegular) |
| `roworderchanged` | A row reorder is requested | `from`, `to` | [Row Drag and Drop](https://rv-grid.com/guide/row/order) |
| `aftersortingapply` | Sorting finishes | Final sorting state and affected row types | [`AfterSortingApplyEvent`](https://rv-grid.com/guide/types/TypeAlias.AfterSortingApplyEvent) |
| `beforefilterapply` | Filtering is about to apply | Filter `collection` | [Filtering events](https://rv-grid.com/guide/filters#event-hooks) |
| `aftercolumnresize` | Column resizing finishes | Resized columns keyed by index | [Column Resize](https://rv-grid.com/guide/column/resize) |
All callback values use the same envelope:
```json
{
"name": "afteredit",
"detail": {
"rowIndex": 0,
"colIndex": 2,
"prop": "amount",
"val": 140,
"type": "rgRow",
"colType": "rgCol"
},
"timestamp": 1784980000000,
"sequence": 1
}
```
- `name` is the lowercase RevoGrid DOM event name.
- `detail` contains the JSON-safe event payload.
- `timestamp` is the browser time in Unix milliseconds.
- `sequence` increases for every emitted bridge event, so two identical
consecutive event payloads still trigger Dash.
For a single-cell edit, `afteredit.detail` keeps only `rowIndex`, `colIndex`,
`prop`, `val` or `value`, `type`, and `colType`. For a range edit, it keeps
`data`, `newRange`, `oldRange`, and `type`. Grid-owned models and collections
are intentionally removed.
### Observe several events
```python
from dash import Input, Output, callback, ctx
import json
@callback(
Output("grid-events", "children"),
Input("orders-grid", "afteredit"),
Input("orders-grid", "afterfocus"),
Input("orders-grid", "aftersortingapply"),
prevent_initial_call=True,
)
def show_grid_event(afteredit, afterfocus, aftersorting):
property_name = ctx.triggered[0]["prop_id"].rsplit(".", 1)[1]
event = {
"afteredit": afteredit,
"afterfocus": afterfocus,
"aftersortingapply": aftersorting,
}[property_name]
return json.dumps(event, indent=2)
```
For callbacks with several inputs, `dash.ctx` identifies exactly which
property triggered the callback.
### Subscribe to any other RevoGrid event
Use `eventListeners` to activate generated event properties that are not active
by default. Their latest payload is published through both the same-name
property and the backwards-compatible `eventData` property:
```python
grid = RevoGrid(
id="orders-grid",
eventListeners=[
"aftergridinit",
"filterconfigchanged",
"sortingconfigchanged",
],
columns=columns,
source=rows,
style={"height": 420},
)
@callback(
Output("generic-event", "children"),
Input("orders-grid", "eventData"),
prevent_initial_call=True,
)
def show_generic_event(event):
return f'{event["sequence"]}: {event["name"]}'
```
Names are deduplicated and listeners are updated when `eventListeners`
changes. Default event names do not need to be listed because their generated
Dash properties already receive them. Runtime plugin events absent from Stencil
metadata continue to update `eventData` only.
Do not subscribe to high-frequency events such as `viewportscroll` unless a
server round trip for every event is intentional.
Browse the [complete Core events table](https://rv-grid.com/guide/api/events) and
[event lifecycle guide](https://rv-grid.com/guide/events-guide) to choose names and understand
event order.
### JSON-safe event serialization
The bridge serializes event details before calling Dash `setProps`:
- strings, finite numbers, booleans, `null`, arrays, and plain objects remain;
- JavaScript `Date` values become ISO strings;
- non-finite numbers, cycles, DOM nodes, and class instances become `null`;
- unsupported object fields such as functions, symbols, and `undefined` are
omitted;
- unsupported array entries become `null`.
This protects callbacks from DOM and grid-internal objects that Dash cannot
transport.
---
# Dash Edit Synchronization
Source: https://rv-grid.com/guide/dash/edit-synchronization
Description: Choose compact edit events or full source synchronization for RevoGrid in Plotly Dash.
# Edit synchronization
Choose the source ownership model deliberately.
### Recommended default: compact edit deltas
`syncSourceOnEdit=False` is the default. RevoGrid applies the edit in the
browser and sends only `afteredit` to Python:
```text
edit in browser -> compact afteredit envelope -> Dash callback
```
This is the right default for large sources, autosave APIs, audit logs, patch
queues, and applications that can persist one changed field at a time.
```python
@callback(
Output("save-status", "children"),
Input("orders-grid", "afteredit"),
prevent_initial_call=True,
)
def persist_edit(event):
detail = event["detail"]
if "prop" not in detail:
return "A range edit was received"
save_cell_change(
row_index=detail["rowIndex"],
field=detail["prop"],
value=detail["val"],
)
return f'Saved row {detail["rowIndex"]}'
```
`save_cell_change` represents the application's persistence layer. In a real
multi-user application, include a stable row identifier in the source and map
the reported `rowIndex` to that identifier.
### Opt in to complete source synchronization
Set `syncSourceOnEdit=True` when a Dash callback genuinely needs the complete
edited source:
```python
RevoGrid(
id="orders-grid",
syncSourceOnEdit=True,
columns=columns,
source=rows,
style={"height": 420},
)
@callback(
Output("row-count", "children"),
Input("orders-grid", "source"),
prevent_initial_call=True,
)
def receive_complete_source(source):
return f"{len(source)} rows received"
```
After each edit, the bridge creates a JSON-safe snapshot and updates `source`
together with `afteredit`. It also recognizes the immediate Dash echo of that
snapshot and does not assign it back to the grid a second time.
This mode costs memory, serialization time, and network bandwidth proportional
to the complete dataset. Leave it disabled when a compact delta is sufficient.
---
# Dash Property Reference
Source: https://rv-grid.com/guide/dash/property-reference
Description: Review supported RevoGrid properties, Python boundary limitations, and troubleshooting for Plotly Dash.
# Complete property reference
The table below is the complete public property surface of
`dash_datagrid.RevoGrid`.
### Dash host and bridge properties
| Property | Python shape | Purpose |
| ---------------------------- | ------------------------ | ------------------------------------------------------------------------ |
| `id` | `str` or Dash pattern ID | Component identifier used by callbacks |
| `className` | `str` | CSS class on the Dash host element |
| `style` | `dict` | Inline host style; normally include a `height` |
| Every public Core event name | `dict` | Latest JSON-safe envelope; generated automatically from Stencil metadata |
| `eventListeners` | `list[str]` | Additional generated or runtime event names to activate |
| `eventData` | `dict` | Latest generic event envelope |
| `syncSourceOnEdit` | `bool`, default `False` | Also update the complete Dash `source` after edits |
### Core data and schema properties
| Property | Python shape | Purpose | Reference |
| -------------------- | ------------ | -------------------------------------- | ---------------------------------------------------------------------- |
| `columns` | `list[dict]` | Regular and grouped column definitions | [Columns](https://rv-grid.com/guide/column) |
| `source` | `list[dict]` | Main row source | [Rows](https://rv-grid.com/guide/row) |
| `pinnedTopSource` | `list[dict]` | Rows in the top pinned viewport | [Pinned rows](https://rv-grid.com/guide/row/pin) |
| `pinnedBottomSource` | `list[dict]` | Rows in the bottom pinned viewport | [Pinned rows](https://rv-grid.com/guide/row/pin) |
| `columnTypes` | `dict` | Named JSON-safe column presets | [Column types](https://rv-grid.com/guide/column/types) |
| `rowDefinitions` | `list[dict]` | Per-row sizes by type and index | [`RowDefinition`](https://rv-grid.com/guide/types/TypeAlias.RowDefinition) |
| `additionalData` | `dict` | Extra plain JSON context | [Advanced configuration](https://rv-grid.com/guide/advanced-configuration#additionaldata) |
### Core layout and interaction properties
| Property | Python shape | Purpose | Reference |
| ---------------- | ---------------- | -------------------------------------------- | ---------------------------------------------------------------- |
| `rowHeaders` | `bool` or `dict` | Row numbers or JSON-safe row-header options | [Row headers](https://rv-grid.com/guide/row/headers) |
| `colSize` | number | Default column width | [Grid size](https://rv-grid.com/guide/grid.size) |
| `rowSize` | number | Default row height | [Row height](https://rv-grid.com/guide/row/height) |
| `rowClass` | `str` | Source field containing the row CSS class | [Rows](https://rv-grid.com/guide/row#row-class-binding) |
| `resize` | `bool` | Allow column resizing | [Column resize](https://rv-grid.com/guide/column/resize) |
| `autoSizeColumn` | `bool` or `dict` | Enable/configure automatic column sizing | [Column autosize](https://rv-grid.com/guide/column/autosize) |
| `stretch` | `bool` or `str` | Fill remaining horizontal space | [Column stretch](https://rv-grid.com/guide/column/stretch) |
| `readonly` | `bool` | Make the complete grid read-only | [Editing](https://rv-grid.com/guide/editing) |
| `applyOnClose` | `bool` | Apply an editor value when the editor closes | [Editing](https://rv-grid.com/guide/editing) |
| `range` | `bool` | Enable cell range selection | [Selection API](https://rv-grid.com/guide/api/selectionFocus) |
| `useClipboard` | `bool` or `dict` | Enable/configure clipboard behavior | [Clipboard](https://rv-grid.com/guide/clipboard) |
| `canFocus` | `bool` | Allow grid cell focus | [Advanced configuration](https://rv-grid.com/guide/advanced-configuration#canfocus) |
| `canMoveColumns` | `bool` | Enable column reordering | [Column ordering](https://rv-grid.com/guide/column/order) |
| `canDrag` | `bool` | Allow the native drag-and-drop path | [Row ordering](https://rv-grid.com/guide/row/order) |
### Core data feature properties
| Property | Python shape | Purpose | Reference |
| ------------- | ---------------- | ------------------------------------ | ------------------------------------------------------- |
| `filter` | `bool` or `dict` | Enable/configure built-in filtering | [Filtering](https://rv-grid.com/guide/filters) |
| `sorting` | `dict` | Apply external sorting configuration | [Sorting](https://rv-grid.com/guide/sorting) |
| `grouping` | `dict` | Configure Core row grouping | [Row grouping](https://rv-grid.com/guide/row/grouping) |
| `trimmedRows` | `dict` | Hide physical main-row indexes | [Rows and trimming](https://rv-grid.com/guide/row#managing-row-visibility) |
| `exporting` | `bool` | Enable the Core export plugin | [Export plugin](https://rv-grid.com/guide/export.plugin) |
### Core rendering and platform properties
| Property | Python shape | Purpose | Reference |
| ---------------------------- | ------------ | ------------------------------------------------------------------ | ------------------------------------------------- |
| `theme` | `str` | RevoGrid theme name | [Themes](https://rv-grid.com/guide/theme) |
| `themeDefinitions` | `list[dict]` | Per-grid custom theme definitions | [Themes](https://rv-grid.com/guide/theme#typed-reusable-themes) |
| `accessible` | `bool` | Enable accessibility behavior | [Accessibility](https://rv-grid.com/guide/wcag) |
| `rtl` | `bool` | Use right-to-left layout | [RTL](https://rv-grid.com/guide/rtl) |
| `frameSize` | number | Off-screen virtualization buffer | [Performance](https://rv-grid.com/guide/performance#framesize) |
| `disableVirtualX` | `bool` | Disable column virtualization | [Performance](https://rv-grid.com/guide/performance#disablevirtualx) |
| `disableVirtualY` | `bool` | Disable row virtualization | [Performance](https://rv-grid.com/guide/performance#disablevirtualy) |
| `virtualX` | `list[str]` | Column dimensions using X virtualization | [Viewports](https://rv-grid.com/guide/viewports) |
| `noHorizontalScrollTransfer` | `bool` | Do not mirror horizontal scroll between viewport sections | [RevoGrid API](https://rv-grid.com/guide/api/revoGrid) |
| `hideAttribution` | `bool` | Hide attribution; use only with the required RevoGrid subscription | [Attribution](https://rv-grid.com/guide/attribution) |
For exact Core defaults and TypeScript types, use the
[RevoGrid component API](https://rv-grid.com/guide/api/revoGrid). The Python signature and
docstring are generated with the package, so `help(RevoGrid)` also lists every
Dash property:
```python
from dash_datagrid import RevoGrid
help(RevoGrid)
```
## Python boundary limitations
### Excluded grid properties
The wrapper intentionally excludes properties whose values require JavaScript
functions, classes, promises, or virtual DOM nodes:
| Excluded Core property | Why it is excluded |
| ---------------------- | -------------------------------------------- |
| `editors` | Values are editor constructors/classes |
| `plugins` | Values are plugin classes |
| `focusTemplate` | Value is a render function |
| `jobsBeforeRender` | Values are browser promises |
| `registerVNode` | Values are virtual nodes or render functions |
Function-valued members nested inside otherwise supported objects are also
unsupported. Examples include custom cell/header templates, custom editor
constructors, custom comparison or parser functions, custom filter functions,
and custom grouping renderers.
### `before*` events cannot cancel server-side
Core `before*` DOM events may be cancelable in JavaScript because a browser
listener can call `preventDefault()` synchronously. A Python Dash callback runs
after a network round trip, so `beforefilterapply` and generic `before*` events
are notifications only. They cannot prevent or rewrite the browser action.
### Imperative methods
The Core API includes methods for selection, scrolling, data access, export,
and targeted updates. Those methods are documented for JavaScript consumers
but are not callable through `dash_datagrid.RevoGrid` in v1. Use declarative
Dash output properties for Python-driven changes.
## Troubleshooting
### The grid has no visible height
Give the component host an explicit height:
```python
RevoGrid(..., style={"height": "60vh", "minHeight": 320})
```
### A prop is not JSON serializable
Normalize DataFrame values, NumPy values, `Decimal`, timestamps, UUIDs, and
custom Python objects before assigning them. Dash must serialize props before
they reach RevoGrid.
### A custom renderer, editor, comparator, or filter does not work
Those APIs require JavaScript functions. They are part of the Core JavaScript
API but outside the v1 Python boundary.
### A `before*` callback did not prevent an action
Python callbacks cannot synchronously cancel browser events. Observe the
resulting event, or implement the behavior declaratively with a new prop value.
### Editing a large source causes large callback requests
Leave `syncSourceOnEdit=False` and consume the compact `afteredit` delta. Full
source synchronization is opt-in.
### A generic event does not update `eventData`
Use the lowercase event name shown in the
[Core events table](https://rv-grid.com/guide/api/events). Auto-discovered events update their
named Dash property and `eventData`; runtime-only plugin events update
`eventData`.
---
# Dash Core API Reference
Source: https://rv-grid.com/guide/dash/core-api-reference
Description: Find the RevoGrid Core API documentation that applies to the Plotly Dash wrapper.
# RevoGrid API reference
These pages are the source of truth behind the Dash wrapper:
| Area | Documentation |
| --- | --- |
| Complete component properties, events, and methods | [RevoGrid API](https://rv-grid.com/guide/api/revoGrid) |
| Complete event name and payload table | [Events API](https://rv-grid.com/guide/api/events) |
| Event ordering and lifecycle diagrams | [Event Patterns](https://rv-grid.com/guide/events-guide) |
| Generated TypeScript type index | [Type reference](https://rv-grid.com/guide/types/README) |
| Columns and column schema | [Columns](https://rv-grid.com/guide/column), [`ColumnRegular`](https://rv-grid.com/guide/types/Interface.ColumnRegular), [`ColumnGrouping`](https://rv-grid.com/guide/types/Interface.ColumnGrouping) |
| Rows, row headers, row sizes, pinning, ordering | [Rows](https://rv-grid.com/guide/row), [Row Headers](https://rv-grid.com/guide/row/headers), [Row Height](https://rv-grid.com/guide/row/height), [Pinned Rows](https://rv-grid.com/guide/row/pin), [Row Order](https://rv-grid.com/guide/row/order) |
| Editing, selection, clipboard | [Editing](https://rv-grid.com/guide/editing), [Selection API](https://rv-grid.com/guide/api/selectionFocus), [Clipboard](https://rv-grid.com/guide/clipboard), [Clipboard API](https://rv-grid.com/guide/api/clipboard) |
| Filtering, sorting, grouping | [Filtering](https://rv-grid.com/guide/filters), [Sorting](https://rv-grid.com/guide/sorting), [Row Grouping](https://rv-grid.com/guide/row/grouping) |
| Sizing and column layout | [Grid Size](https://rv-grid.com/guide/grid.size), [Autosize](https://rv-grid.com/guide/column/autosize), [Resize](https://rv-grid.com/guide/column/resize), [Stretch](https://rv-grid.com/guide/column/stretch), [Pin Columns](https://rv-grid.com/guide/column/pin), [Column Order](https://rv-grid.com/guide/column/order) |
| Source ownership and remote data | [Data Sync](https://rv-grid.com/guide/data-sync), [Server-side Data](https://rv-grid.com/guide/server-side-data), [Real-time Updates](https://rv-grid.com/guide/realtime-updates) |
| Virtualization and indexes | [Performance](https://rv-grid.com/guide/performance), [Viewports](https://rv-grid.com/guide/viewports) |
| Themes, accessibility, RTL | [Themes](https://rv-grid.com/guide/theme), [Accessibility](https://rv-grid.com/guide/wcag), [RTL](https://rv-grid.com/guide/rtl) |
| Export | [Export Plugin](https://rv-grid.com/guide/export.plugin), [Excel Export](https://rv-grid.com/guide/data-grid-export-excel), [PDF Export](https://rv-grid.com/guide/pdf-export) |
The Core API pages also document browser-only methods and function-valued
types. Use the [complete property reference](https://rv-grid.com/guide/dash/property-reference) and
[Python boundary limitations](https://rv-grid.com/guide/dash/property-reference#python-boundary-limitations) on this page to
determine which parts are available in Dash.
---
# Vue 3 Data Grid
Source: https://rv-grid.com/guide/vue3
Description: Learn how to use RevoGrid in Vue 3 with Composition API or Options API, pass columns and source data, access instance methods, and build custom renderers.
RevoGrid fits naturally into Vue 3 applications when you need a fast grid with native component integrations. You can use it from either the Composition API or the Options API, and still rely on the same core RevoGrid methods and events.
::: info
This guide assumes your Vue project already exists. If not, start with the official [Vue quick start](https://vuejs.org/guide/quick-start).
:::
## Install your Vue Data Grid
Install [RevoGrid for Vue](https://github.com/revolist/vue3-datagrid) using the following command:
::: code-group
```npm
npm i @revolist/vue3-datagrid
```
```pnpm
pnpm add @revolist/vue3-datagrid
```
```yarn
yarn add @revolist/vue3-datagrid
```
```bun
bun add @revolist/vue3-datagrid
```
:::
## Composition API setup
```vue
```
## Options API setup
```vue
```
## Passing `columns` and `source`
The most common Vue pattern is:
- keep `columns` in component state
- pass `source` as reactive data
- use grid methods when you need imperative actions like scrolling, focusing, or opening an editor
# Get Started with Vue 3 Data Grid Demo - Options API
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue.sample.options.example.vue) [Codesandbox](https://codesandbox.io/p/sandbox/rg-start-vue-3-options-ap-8mlqjx)
::: code-group
<<< @/demo/vue/vue.sample.options.example.vue
:::
## Accessing grid instance methods
To call a method on the underlying grid, use the wrapped Web Component instance:
```js
// ✅ Correct
myComponentRef.value.$el.someMethod();
// ❌ Incorrect
myComponentRef.value.someMethod();
```
This matters for methods like `setCellEdit`, `scrollToRow`, `setCellsFocus`, and `getVisibleSource`.
## Custom renderers and editors
Use these guides for framework-native customization:
- [Vue 3 Cell Template](https://rv-grid.com/guide/vue3/renderer)
- [Vue 3 Cell Editor](https://rv-grid.com/guide/vue3/editor)
## Event handling
For application workflows, the most useful events are:
- `beforeedit`
- `afteredit`
- `beforefilterapply`
- `beforecellfocus`
## SSR and client-only behavior
Like the core Web Component, RevoGrid depends on browser APIs. If you use Vue in an SSR setup, render the grid on the client side or guard the component load accordingly.
## Related guides
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Advanced Configuration](https://rv-grid.com/guide/advanced-configuration)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
---
# Vue Data Grid Cell Template
Source: https://rv-grid.com/guide/vue3/renderer
Description: Learn about cell template rendering for Vue 3 Data Grid, enabling smooth integration of custom Vue components within grid cells.
RevoGrid provide a way to render native components inside of cells.
::: warning
If you are aiming for the faster render we are recommending to stick with native VNode render.
:::
::: tip
Check [ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel) for mode information about input types.
:::
## Vue 3 - Native Cell Component (Composition API)
```
## Why Use Custom Cell Rendering?
RevoGrid’s native cell rendering enables you to:
- **Embed Components**: Render complex or interactive UI elements inside grid cells, such as buttons, images, input fields, or custom widgets.
- **Dynamic Content**: Customize each cell’s content based on the data it represents, such as formatting or conditional rendering.
- **Interactivity**: Make cells interactive with event listeners and component lifecycle methods, improving the overall user experience.
---
# Vue Data Grid Editor
Source: https://rv-grid.com/guide/vue3/editor
Description: Discover how to utilize Vue 3 Data Grid for native editor rendering, enabling seamless in-cell editing using Vue components.
RevoGrid provides a way to render native components as editor.
::: tip
You can access close and save callbacks in properties. Check [editor](https://rv-grid.com/guide/cell/editor) and `EditorCtr` type for more.
:::
# Vue 3 Data Grid Cell Editor component (Composition API)
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue.editor.composition.example.vue) [Codesandbox](https://codesandbox.io/p/sandbox/rg-editor-vue-3-composition-api-sl8vvw)
::: code-group
<<< @/demo/vue/vue.editor.composition.example.vue
<<< @/demo/vue/vue.editor.composition.example-editor.vue
:::
## Data Grid App
```vue
// vue.editor.composition.example.vue
```
## Data Grid Editor Component
```vue
// vue.editor.composition.example-editor.vue
```
---
# Svelte Data Grid
Source: https://rv-grid.com/guide/svelte
Description: Build fast, scalable Svelte Data Grid with support for virtual rows and columns.
# Svelte Data Grid
## Svelte Data Grid Demo
Use this Svelte demo to embed RevoGrid in a Svelte application with virtual rows, virtual columns, and editable data grid behavior.
[](https://codesandbox.io/p/devbox/rg-start-svelte-k7xdsh?embed=1&file=%2Fsrc%2Froutes%2F%2Bpage.svelte)
::: warning
We have updated our latest version to support **Svelte 5** following its official release. 🎉
Read more about the announcement here: [Svelte 5 is Alive](https://svelte.dev/blog/svelte-5-is-alive).
If you want to continue using **Svelte 4**, please switch to the [svelte-4](https://github.com/revolist/svelte-datagrid/tree/svelte-4) branch or use version prior to 4.11.0.
:::
RevoGrid provide special wrapper based on [stenciljs svelte adapter](https://www.npmjs.com/package/@stencil/svelte-output-target). Just import it to your project and it can be used as part of svelte system.
## Install your Svelte Data Grid
Install RevoGrid for Svelte using the following command:
::: code-group
```npm
npm install @revolist/svelte-datagrid
```
```pnpm
pnpm add @revolist/svelte-datagrid
```
```yarn
yarn add @revolist/svelte-datagrid
```
```bun
bun add @revolist/svelte-datagrid
```
## Example
<<< @/demo/svelte/svelte.sample.svelte
## SvelteKit
::: warning
SSR is not compatible with RevoGrid out of the box because it depends on the browser environment.
There is no documentation on hybrid projects with server-side rendering (SSR) for SvelteKit at this time. This is going to be added in the future.
:::
Here are two approaches to use RevoGrid in a SvelteKit project:
### Option 1: Disable SSR
You can disable SSR for the entire page where RevoGrid is used. This ensures the page is rendered only on the client.
Add a `+page.js` (For JavaScript Projects) or `+page.ts` (For TypeScript Projects) file in the same directory as your `+page.svelte`:
```typescript
// +page.js or +page.ts
export const ssr = false;
```
With this setup, your +page.svelte can directly use RevoGrid:
```svelte
```
### Option 2: Use CSR (Client-Side Rendering)
If you don’t want to disable SSR for the entire page, you can render RevoGrid only in the browser using CSR loading techniques.
#### CSR: Conditional Rendering Based on the Browser
Use the browser variable from SvelteKit to ensure RevoGrid is only rendered on the client side:
```svelte
{#if browser}
{:else}
RevoGrid is not available during server-side rendering.
{/if}
```
#### CSR: Lazy-Loading
You can dynamically import RevoGrid using Svelte’s onMount lifecycle method. This ensures the library is only loaded after the page is mounted in the browser:
```svelte
{#if RevoGrid}
{:else}
Loading RevoGrid...
{/if}
```
Check out our repo for example: [SvelteKit](https://github.com/revolist/revogrid-svelte-kit)
When to Use These Options?
- Disabling SSR for the Page: Use this if the entire page depends on RevoGrid and SSR isn’t necessary.
- Client-Side Rendering (CSR) for RevoGrid: Use this if you need other parts of the page to be server-rendered but still want to use RevoGrid in the browser.
With these methods, you can successfully integrate RevoGrid into your SvelteKit project while handling its lack of SSR compatibility.
## Related guides
- [Programmatic Grid Control](https://rv-grid.com/guide/programmatic-control)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
- [Event Patterns and Lifecycles](https://rv-grid.com/guide/events-guide)
---
# Svelte Data Grid Cell Template
Source: https://rv-grid.com/guide/svelte/renderer
Description: Render native Svelte components inside RevoGrid cells with the Svelte Data Grid wrapper.
RevoGrid provide a way to render native components inside of cells.
::: warning
If you are aiming for the faster render we are recommending to stick with native VNode render.
:::
::: tip
Check [ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel) for mode information about input types.
:::
Use `Template(Component)` from `@revolist/svelte-datagrid` to render a Svelte component inside a `cellTemplate`.
::: tip
`Template(Component)` is explicit by design. Native RevoGrid templates like `cellTemplate(h, props)` are still supported, and compiled Svelte components are also functions at runtime, so raw `cellTemplate: Component` is not auto-detected.
:::
## Basic Setup
```svelte
```
## Cell Component
```svelte
```
The Svelte component receives flat cell props such as `value`, `model`, `prop`, `rowIndex`, `colIndex`, `column`, `data`, `providers`, and `addition`.
## Why Use Custom Cell Rendering?
RevoGrid’s native cell rendering enables you to:
- **Embed Components**: Render complex or interactive UI elements inside grid cells, such as buttons, images, input fields, or custom widgets.
- **Dynamic Content**: Customize each cell’s content based on the data it represents, such as formatting or conditional rendering.
- **Interactivity**: Make cells interactive with event listeners and component lifecycle methods, improving the overall user experience.
---
# Svelte Data Grid Editor
Source: https://rv-grid.com/guide/svelte/editor
Description: Build custom RevoGrid editors with native Svelte components.
RevoGrid provides a way to render native components as editor.
::: tip
You can access close and save callbacks in properties. Check [editor](https://rv-grid.com/guide/cell/editor) and `EditorCtr` type for more.
:::
Use `Editor(Component)` from `@revolist/svelte-datagrid` to register a Svelte component as a custom editor.
## Basic Setup
```svelte
```
## Editor Component
```svelte
```
The editor component receives flat props from `EditorType`, including the current edit-cell data plus:
- `column`: the column data schema model.
- `save(value, preventFocus?)`: saves the value and closes the editor.
- `close(focusNext?)`: closes the editor without saving.
If the editor should participate in autosave-on-close, export `getValue()` from the Svelte component.
## Why Use Custom Editors?
With native editor rendering, you can:
- **Customize the Editing Experience**: Use any React component as a custom editor, providing a tailored user interface for editing data directly in the grid.
- **Build Complex Editors**: Embed interactive elements such as date pickers, dropdowns, or custom forms inside cells, which would be impossible with simple input fields alone.
- **Improve Usability**: Create inline editors that match your application’s UI, improving consistency and enhancing the overall user experience.
---
# Svelte Tree Data Grid
Source: https://rv-grid.com/guide/svelte/tree
Description: Build a Svelte tree data grid with the free RevoGrid core tree pattern, then use RevoGrid Pro TreeDataPlugin for expandable hierarchy controls and sticky parent rows.
Svelte can use the free/core tree pattern with the same RevoGrid Web Component API: flatten your hierarchy, keep a `level` field, and render indentation in a cell template.
::: info
The shared live core tree demo is currently published for TypeScript, React, Vue 3, and Angular. Svelte uses the same flat `source` and cell-template approach.
:::
Tree-like rows do not require Pro when your application only needs a visual hierarchy. The free/core approach is to flatten parent-child records into display order, add a `level` field, and render indentation in a cell template.
This keeps RevoGrid simple: the grid receives a normal `source` array, virtualization still works, and your application owns the hierarchy transformation.
## Tree model
Start with records that have an ID and a parent ID:
```ts
const inputData = [
{ id: 4, parentId: 0, name: 'Antoni father for 2' },
{ id: 5, parentId: 4, name: 'Odin' },
{ id: 6, parentId: 4, name: 'John' },
{ id: 1, parentId: 0, name: 'Mary mother for 2' },
{ id: 2, parentId: 1, name: 'Howard has also 2' },
];
```
Convert that data into a flat display list before assigning it to the grid:
```ts
function buildTreeData(rows: typeof inputData, rootParentId = 0) {
const childrenByParent = new Map();
for (const row of rows) {
const children = childrenByParent.get(row.parentId) ?? [];
children.push(row);
childrenByParent.set(row.parentId, children);
}
const result: Array<(typeof inputData)[number] & { level: number }> = [];
function appendChildren(parentId: number, level = 0) {
for (const child of childrenByParent.get(parentId) ?? []) {
result.push({ ...child, level });
appendChildren(child.id, level + 1);
}
}
appendChildren(rootParentId);
return result;
}
```
## Indented cell template
The core demo uses a normal cell template to show hierarchy depth:
```ts
const columns = [
{
prop: 'name',
name: 'Tree',
size: 300,
cellTemplate(h, { value, model }) {
return h(
'div',
{
style: {
marginLeft: `${(model?.level ?? 0) * 30}px`,
},
},
value || '',
);
},
},
{
prop: 'level',
readonly: true,
},
];
```
Use the core approach when the hierarchy is read-only or mostly decorative: category outlines, simple nested lists, document sections, or a tree table where your app handles all expand/collapse logic outside the grid.
## Core limits
The free/core pattern is intentionally lightweight. It does not add built-in expand/collapse controls, automatic parent-child visibility, tree-aware drag-and-drop, sticky parent rows, or parent/descendant row selection behavior. Those behaviors belong in the Pro Tree Data plugin.
## Svelte notes
- Keep the input hierarchy and flattened `treeData` in component state or a store.
- Reassign `treeData` when the hierarchy changes.
- In SvelteKit, render RevoGrid only on the client, as described in the main Svelte guide.
```svelte
```
## Pro Tree Data
RevoGrid Pro adds a dedicated `TreeDataPlugin` for advanced data grid tree structures. It keeps the original `source` flat, computes hierarchy metadata internally, and renders tree controls in the column marked with `tree: true`.
::: info RevoGrid Pro
Use the Pro plugin when hierarchy is not just indentation: users need expand/collapse controls, persistent expansion state, filtering and sorting with hierarchy awareness, row selection across descendants, drag-and-drop reparenting, or sticky parent rows while scrolling long branches.
:::
### Pro data model
The Pro model also starts from stable IDs and parent IDs:
```ts
type TeamRow = {
id: string;
parentId: string | null;
name: string;
role: string;
budget: number;
};
const source: TeamRow[] = [
{ id: 'eng', parentId: null, name: 'Engineering', role: 'Department', budget: 850000 },
{ id: 'platform', parentId: 'eng', name: 'Platform', role: 'Team', budget: 320000 },
{ id: 'api', parentId: 'platform', name: 'API', role: 'Squad', budget: 140000 },
{ id: 'design', parentId: null, name: 'Design', role: 'Department', budget: 260000 },
];
```
Unlike the core example, you do not add `level` yourself. The plugin derives level, visibility, expanded state, and child metadata from the tree config.
### Pro column and plugins
Mark one hierarchy column with `tree: true`, register `TreeDataPlugin`, and pass the `tree` config:
```ts
import {
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
TREE_EXPAND_ALL_EVENT,
TREE_COLLAPSE_ALL_EVENT,
} from '@revolist/revogrid-pro';
const columns = [
{
prop: 'name',
name: 'Team',
size: 300,
tree: true,
sortable: true,
rowSelect: true,
rowDrag: true,
},
{ prop: 'role', name: 'Role', size: 160 },
{ prop: 'budget', name: 'Budget', size: 140 },
];
const plugins = [
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
];
const tree = {
idField: 'id',
parentIdField: 'parentId',
rootParentId: null,
expandedRowIds: new Set(['eng']),
stickyParents: true,
};
```
Framework wrappers pass these values as props or bindings. Plain TypeScript assigns them to the `revo-grid` element.
### Expand and collapse controls
The Pro plugin exposes events for toolbar buttons and external controls:
```ts
grid.dispatchEvent(new CustomEvent(TREE_EXPAND_ALL_EVENT));
grid.dispatchEvent(new CustomEvent(TREE_COLLAPSE_ALL_EVENT));
```
Use `expandAll: true` when every branch should open on first render. Use `expandedRowIds` when you want controlled initial state or persisted expansion.
### Production guidance
- Keep IDs stable across refreshes so expanded state survives data updates.
- Use `parentId: null` or another explicit `rootParentId` consistently.
- Keep only one tree column active; use normal columns for the rest of the row data.
- Combine tree data with virtualization for large hierarchies instead of rendering nested DOM lists.
- Add `StickyCellsPlugin` only when sticky parent rows are useful for long branches.
- Reconcile drag-and-drop changes in your application store before saving to the backend.
- Prefer flat server payloads for large trees; they are simpler to page, diff, validate, and persist.
## Related guides
- [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data)
- [Row Ordering](https://rv-grid.com/guide/row/order)
- [Row Selection](https://rv-grid.com/guide/row/selection.pro)
- [Filtering](https://rv-grid.com/guide/filters)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
---
# Demo Svelte Data Grid
Source: https://rv-grid.com/guide/demos/svelte/svelte-datagrid
Description: Learn how to integrate RevoGrid with Svelte to build fast, scalable data grids with support for virtual rows and columns.
## Svelte Data Grid Demo
Use this Svelte demo to embed RevoGrid in a Svelte application with virtual rows, virtual columns, and editable data grid behavior.
[](https://codesandbox.io/p/devbox/rg-start-svelte-k7xdsh?embed=1&file=%2Fsrc%2Froutes%2F%2Bpage.svelte)
---
# Stencil Data Grid
Source: https://rv-grid.com/guide/stencil
Description: Learn how to use Stencil Data Grid to build fast, scalable data applications with support for virtual rows and columns.
# Stencil Data Grid
This page covers the key concepts of RevoGrid - a high-performance, customizable StencilJS Table and StencilJS Data Grid for managing large datasets.
# Stencil Data Grid Demo
Use this Stencil demo to add RevoGrid as a Web Component and test the setup in StackBlitz.
[Edit RG Start (StencilJs)](https://stackblitz.com/edit/stencil-template-aiden-xadqm4?file=src%2Fcomponents%2Fmy-component%2Fmy-component.tsx)
## What is StencilJS?
Stencil aims to eliminate the need for writing components with a specific framework’s API. It achieves this by leveraging standardized web platform APIs compatible with all modern browsers. By using the browser’s low-level component model, which underpins all frameworks, Stencil components can function both within a framework and independently.
Integrating web components directly into existing applications can be challenging due to the varying levels of support frameworks have for vanilla web components.
For more information about getting started with StencilJS, visit the [official StencilJS documentation](https://stenciljs.com/docs/getting-started).
## Install your React Data Grid
Install RevoGrid for React using the following command:
::: code-group
```npm
npm i @revolist/react-datagrid
```
```pnpm
pnpm add @revolist/react-datagrid
```
```yarn
yarn add @revolist/react-datagrid
```
```bun
bun add @revolist/react-datagrid
```
:::
## Usage
Create a StencilJS component and import the necessary modules.
Define the custom elements and configure your component as follows:
<<< @/demo/stencil/stencil.sample.tsx
### Explanation
1. **Import Statements**: Import necessary modules from `@revolist/revogrid` and StencilJS core.
2. **Component Decorator**: Use the `@Component` decorator to define a new Stencil component with the tag name `my-component`.
3. **Column Definition**: Define the columns for the grid using the `ColumnRegular` type.
4. **Data Source**: Define the data source for the grid.
5. **Lifecycle Method**: Use the `componentWillLoad` lifecycle method to initialize the RevoGrid custom elements.
6. **Render Method**: Render the `revo-grid` component with the defined columns and data source, and enable filtering.
That's it! Your StencilJS project is now set up to use RevoGrid.
---
# StencilJs Getting Started
Source: https://rv-grid.com/guide/demos/stencil/stencil.sample
Description: Start a Stencil data grid demo with RevoGrid as a Web Component, including an editable StackBlitz example.
# Stencil Data Grid Demo
Use this Stencil demo to add RevoGrid as a Web Component and test the setup in StackBlitz.
[Edit RG Start (StencilJs)](https://stackblitz.com/edit/stencil-template-aiden-xadqm4?file=src%2Fcomponents%2Fmy-component%2Fmy-component.tsx)
---
# Vue 2 Data Grid
Source: https://rv-grid.com/guide/vue2
Description: Use Vue 2 Data Grid to build fast, scalable data applications with support for virtual rows and columns.
This page covers the key concepts of RevoGrid - a high-performance, customizable Vue 2 Table and Vue 2 Data Grid for managing large datasets.
# Getting Started - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-start-vue-2-3zl8hd)
## Install your Vue 2 Data Grid
Install [RevoGrid for Vue 2](https://www.npmjs.com/package/@revolist/vue-datagrid) using the following command:
::: code-group
```npm
npm i @revolist/vue-datagrid
```
```pnpm
pnpm add @revolist/vue-datagrid
```
```yarn
yarn add @revolist/vue-datagrid
```
```bun
bun add @revolist/vue-datagrid
```
:::
## Vue 2 Data Grid Usage
```vue
// App.vue
```
# Getting Started - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-start-vue-2-3zl8hd)
## Check out our Vue Data Grid examples
---
# Vue 2 Native Cell Render Support in RevoGrid
Source: https://rv-grid.com/guide/vue2/renderer
Description: Explore native cell rendering support in RevoGrid for Vue 2, enabling seamless integration of custom Vue components inside grid cells.
# Vue 2 Data Grid Cell Template
RevoGrid provide a way to render native components inside of cells.
::: warning
If you are aiming for the faster render we are recommending to stick with native VNode render.
:::
::: tip
Check [ColumnDataSchemaModel](https://rv-grid.com/guide/types/TypeAlias.ColumnDataSchemaModel) for mode information about input types.
:::
Create component which you would like to be presented as cell.
You can use `props` to access row model object, column property or other props described in `ColumnDataSchemaModel`.
Check [interfaces](https://github.com/revolist/revogrid/blob/master/src/interfaces.d.ts) for mode information about types.
# Native Cell Component - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-cell-vue-2-78q5fl)
## App
```vue
// App.vue
// App.vue
```
## Cell template
```vue
// Cell.vue
Custom cell
```
## Why Use Custom Cell Rendering?
RevoGrid’s native cell rendering enables you to:
- **Embed Components**: Render complex or interactive UI elements inside grid cells, such as buttons, images, input fields, or custom widgets.
- **Dynamic Content**: Customize each cell’s content based on the data it represents, such as formatting or conditional rendering.
- **Interactivity**: Make cells interactive with event listeners and component lifecycle methods, improving the overall user experience.
## Check out our Vue Data Grid examples
---
# Vue 2 Data Grid Editor
Source: https://rv-grid.com/guide/vue2/editor
Description: Discover how to use Vue 2 for native editor rendering in Vue 2 Data Grid, allowing for custom in-cell editing with Vue components.
RevoGrid provides a way to render native components as editor.
::: tip
You can access close and save callbacks in properties. Check [editor](https://rv-grid.com/guide/cell/editor) and `EditorCtr` type for more.
:::
# Native Editor Component - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-editor-vue-2-9zr8ng)
## App
```vue
// App.vue
```
## Editor
```vue
// Editor.vue
```
## Check out our Vue Data Grid examples
---
# TanStack Integration
Source: https://rv-grid.com/guide/tanstack
Description: Integrate RevoGrid with TanStack to build fast, scalable data grids with support for virtual rows and columns.
# Getting Started with TanStack
[TanStack](https://tanstack.com/table/latest/docs/introduction) is a popular framework for building table data layers. However, RevoGrid offers a more comprehensive solution by incorporating all the features of [TanStack](https://tanstack.com/table/latest/docs/introduction), along with advanced rendering, virtual scrolling, and column-level optimizations for superior performance. If you're transitioning from an existing TanStack architecture or want to quickly prototype, this guide will help you integrate [TanStack](https://tanstack.com/table/latest/docs/introduction) with RevoGrid.
We strongly recommend using RevoGrid's native features for the best performance. It is specifically designed to handle advanced rendering and optimize every aspect of DOM manipulation, ensuring an efficient experience.
RevoGrid operates on the column level, which allows for superior performance, whereas TanStack manages data at the row level.
The following example shows how to use TanStack with RevoGrid to create columns, bind data, and manage interactions.
## TanStack Data Grid Demo with RevoGrid
Use this demo to compare how TanStack Table data models can be rendered through RevoGrid in Vue and React applications.
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/DemoTanstack.vue)
::: code-group
<<< @/demo/vue/DemoTanstack.vue[Vue example]
<<< @/demo/react/react.tanstack.tsx[React example]
<<< @/demo/tanstack/utils.ts
<<< @/demo/makeData.ts
:::
## Summary
Integrating TanStack with RevoGrid allows you to leverage the row-level operations provided by TanStack, while taking advantage of RevoGrid's optimized performance and advanced rendering capabilities, including virtual scrolling and efficient DOM handling.
For a smooth migration or quick experimentation, this setup provides a great foundation, but remember, RevoGrid's built-in features are crafted for peak performance and user experience.
---
# TanStack Tree Data Grid
Source: https://rv-grid.com/guide/tanstack/tree
Description: Combine TanStack state management with the free RevoGrid core tree pattern, then use RevoGrid Pro TreeDataPlugin for expandable hierarchy controls and sticky parent rows.
TanStack can own query, filter, sorting, and expansion state while RevoGrid renders the virtualized grid surface. Start with the free/core tree pattern by deriving a flat display list from TanStack-managed rows.
::: info
Tree rendering is still handled by RevoGrid. TanStack can own the application state around the tree, while RevoGrid receives a flat `source` and renders the cells.
:::
Tree-like rows do not require Pro when your application only needs a visual hierarchy. The free/core approach is to flatten parent-child records into display order, add a `level` field, and render indentation in a cell template.
This keeps RevoGrid simple: the grid receives a normal `source` array, virtualization still works, and your application owns the hierarchy transformation.
## Tree model
Start with records that have an ID and a parent ID:
```ts
const inputData = [
{ id: 4, parentId: 0, name: 'Antoni father for 2' },
{ id: 5, parentId: 4, name: 'Odin' },
{ id: 6, parentId: 4, name: 'John' },
{ id: 1, parentId: 0, name: 'Mary mother for 2' },
{ id: 2, parentId: 1, name: 'Howard has also 2' },
];
```
Convert that data into a flat display list before assigning it to the grid:
```ts
function buildTreeData(rows: typeof inputData, rootParentId = 0) {
const childrenByParent = new Map();
for (const row of rows) {
const children = childrenByParent.get(row.parentId) ?? [];
children.push(row);
childrenByParent.set(row.parentId, children);
}
const result: Array<(typeof inputData)[number] & { level: number }> = [];
function appendChildren(parentId: number, level = 0) {
for (const child of childrenByParent.get(parentId) ?? []) {
result.push({ ...child, level });
appendChildren(child.id, level + 1);
}
}
appendChildren(rootParentId);
return result;
}
```
## Indented cell template
The core demo uses a normal cell template to show hierarchy depth:
```ts
const columns = [
{
prop: 'name',
name: 'Tree',
size: 300,
cellTemplate(h, { value, model }) {
return h(
'div',
{
style: {
marginLeft: `${(model?.level ?? 0) * 30}px`,
},
},
value || '',
);
},
},
{
prop: 'level',
readonly: true,
},
];
```
Use the core approach when the hierarchy is read-only or mostly decorative: category outlines, simple nested lists, document sections, or a tree table where your app handles all expand/collapse logic outside the grid.
## Core limits
The free/core pattern is intentionally lightweight. It does not add built-in expand/collapse controls, automatic parent-child visibility, tree-aware drag-and-drop, sticky parent rows, or parent/descendant row selection behavior. Those behaviors belong in the Pro Tree Data plugin.
## TanStack notes
- Keep row IDs and parent IDs stable in your TanStack data model.
- Derive the flattened tree rows from TanStack state.
- Persist custom expansion state beside table filters, sorting, or query state if you build free expand/collapse controls.
- Pass RevoGrid a flat `source`; do not render nested row components inside the grid.
```ts
const treeData = buildTreeData(rowsFromQuery);
```
## Pro Tree Data
RevoGrid Pro adds a dedicated `TreeDataPlugin` for advanced data grid tree structures. It keeps the original `source` flat, computes hierarchy metadata internally, and renders tree controls in the column marked with `tree: true`.
::: info RevoGrid Pro
Use the Pro plugin when hierarchy is not just indentation: users need expand/collapse controls, persistent expansion state, filtering and sorting with hierarchy awareness, row selection across descendants, drag-and-drop reparenting, or sticky parent rows while scrolling long branches.
:::
### Pro data model
The Pro model also starts from stable IDs and parent IDs:
```ts
type TeamRow = {
id: string;
parentId: string | null;
name: string;
role: string;
budget: number;
};
const source: TeamRow[] = [
{ id: 'eng', parentId: null, name: 'Engineering', role: 'Department', budget: 850000 },
{ id: 'platform', parentId: 'eng', name: 'Platform', role: 'Team', budget: 320000 },
{ id: 'api', parentId: 'platform', name: 'API', role: 'Squad', budget: 140000 },
{ id: 'design', parentId: null, name: 'Design', role: 'Department', budget: 260000 },
];
```
Unlike the core example, you do not add `level` yourself. The plugin derives level, visibility, expanded state, and child metadata from the tree config.
### Pro column and plugins
Mark one hierarchy column with `tree: true`, register `TreeDataPlugin`, and pass the `tree` config:
```ts
import {
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
TREE_EXPAND_ALL_EVENT,
TREE_COLLAPSE_ALL_EVENT,
} from '@revolist/revogrid-pro';
const columns = [
{
prop: 'name',
name: 'Team',
size: 300,
tree: true,
sortable: true,
rowSelect: true,
rowDrag: true,
},
{ prop: 'role', name: 'Role', size: 160 },
{ prop: 'budget', name: 'Budget', size: 140 },
];
const plugins = [
TreeDataPlugin,
RowOrderPlugin,
RowSelectPlugin,
StickyCellsPlugin,
];
const tree = {
idField: 'id',
parentIdField: 'parentId',
rootParentId: null,
expandedRowIds: new Set(['eng']),
stickyParents: true,
};
```
Framework wrappers pass these values as props or bindings. Plain TypeScript assigns them to the `revo-grid` element.
### Expand and collapse controls
The Pro plugin exposes events for toolbar buttons and external controls:
```ts
grid.dispatchEvent(new CustomEvent(TREE_EXPAND_ALL_EVENT));
grid.dispatchEvent(new CustomEvent(TREE_COLLAPSE_ALL_EVENT));
```
Use `expandAll: true` when every branch should open on first render. Use `expandedRowIds` when you want controlled initial state or persisted expansion.
### Production guidance
- Keep IDs stable across refreshes so expanded state survives data updates.
- Use `parentId: null` or another explicit `rootParentId` consistently.
- Keep only one tree column active; use normal columns for the rest of the row data.
- Combine tree data with virtualization for large hierarchies instead of rendering nested DOM lists.
- Add `StickyCellsPlugin` only when sticky parent rows are useful for long branches.
- Reconcile drag-and-drop changes in your application store before saving to the backend.
- Prefer flat server payloads for large trees; they are simpler to page, diff, validate, and persist.
## Related guides
- [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data)
- [Row Ordering](https://rv-grid.com/guide/row/order)
- [Row Selection](https://rv-grid.com/guide/row/selection.pro)
- [Filtering](https://rv-grid.com/guide/filters)
- [Grid Performance and Virtualization](https://rv-grid.com/guide/performance)
---
# TanStack Data Grid Demo with RevoGrid
Source: https://rv-grid.com/guide/demos/tanstack
Description: Explore a TanStack Table integration demo using RevoGrid for high-performance rendering, large datasets, and Vue and React examples.
## TanStack Data Grid Demo with RevoGrid
Use this demo to compare how TanStack Table data models can be rendered through RevoGrid in Vue and React applications.
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/DemoTanstack.vue)
::: code-group
<<< @/demo/vue/DemoTanstack.vue[Vue example]
<<< @/demo/react/react.tanstack.tsx[React example]
<<< @/demo/tanstack/utils.ts
<<< @/demo/makeData.ts
:::
---
# Licensing
Source: https://rv-grid.com/guide/licensing
# Licensing
RevoGrid is an open-core, MIT-licensed Data Grid library. Purchase a [commercial license](https://rv-grid.com/pro) for advanced features and support.
## MIT vs. Commercial licenses
The Revolist team has been building MIT-licensed components and we’re committed to the continued advancement of our open-source libraries. Anything we release under an MIT license will remain MIT-licensed forever.
We offer commercial licenses to developers who need the most advanced components and features that can’t reasonably be maintained by the open-source community alone. These licenses make it possible for us to support a full-time staff of engineers.
Rest assured that when we release features commercially, it’s only because we believe you won’t find a better MIT-licensed alternative anywhere else.
See the [Pricing page](https://rv-grid.com/pro) for a detailed feature comparison.
## Plans
### Community plan
The free Community version of RevoGrid contains components and features that we believe are maintainable by contributions from the open-source community. It’s published under an MIT license and it’s free forever.
### Pro
The Pro version is available under a commercial license and is distributed through an [advanced portal](https://pro.rv-grid.com/) aimed at providing comprehensive user support and extended documentation. [This portal](https://pro.rv-grid.com/) offers users exclusive access to detailed guides, use case examples, troubleshooting, and more to help streamline the development process.
#### Light plan
RevoGrid Pro expands on the Community version with more advanced features and functionality. The Pro version comes with cell merge, formula, charts, and excel export; you also gain access to the advanced column stretching, and expandable Tree View.
The Pro version is available under a commercial license — visit the [Pricing page](https://rv-grid.com/pro) for details.
#### Advanced plan
Unlocks the most advanced features of RevoGrid, including the JavaScript Pivot Table component, Gantt Chart, AI, premium support, private GitHub repository access, totals, drill-down, field panels, custom aggregations, and server-side analytics contracts. It also includes everything offered in the Pro Lite plan.
The Pro Advanced version is available under a commercial license—visit the [Licensing page](https://rv-grid.com/pro/policies/license) for details.
## Upgrading
The npm packages of any given plan are an extension for the Community version. To upgrade, you must install the respective paid package and add all imports accordingly.
Below are upgrading scenarios:
### From Community to Pro
Install the Pro package, then update all imports accordingly:
```typescript
import RevoGrid from '@revolist/vue3-datagrid';
+import { PivotPlugin } from '@revolist/revogrid-pro';
```
### From Pro to Pro Advanced
Contact us to upgrade to Pro Advanced.
### Evaluation (trial) access
Yes, you can evaluate RevoGrid Pro before purchasing. The public trial lasts 30 days and can be installed immediately by teams that need to validate Pro or Pro Advanced modules.
Start with the [Get Pro Trial](https://rv-grid.com/trial) page for installation instructions, public demo links, trial limits, and the path from evaluation to production.
For production license quantity details, see the relevant clause in the [EULA](https://rv-grid.com/pro/policies/license).
---
# Evaluate RevoGrid Pro
Source: https://rv-grid.com/trial
Description: Start evaluating RevoGrid Pro immediately with public trial access, a no-login npm registry, and a ready-to-run public starter.
This page is rendered from VitePress frontmatter and Vue components; no standalone Markdown body is available in the normalized export.
---
# Considering Removing the Attribution? 🤔
Source: https://rv-grid.com/guide/attribution
# Considering Removing the Attribution? 🤔
If you’re thinking about removing the attribution, we’d first like to mention:
**If you’re using RevoGrid at your organization and making money from it, we rely on your support to keep RevoGrid developed and maintained under an MIT License.** Before you remove the attribution, see [the ways you can support RevoGrid](https://rv-grid.com/pro) to keep it running.
Are you using RevoGrid for a **personal project**? Awesome! 🎉 Go ahead and remove the attribution. You can support us by:
- Reporting any bugs 🐞 you find
- Sending us screenshots 📸 of your projects
- Starring us ⭐ on [GitHub](https://github.com/revolist/revogrid)
If you start making money using RevoGrid or use it in an organization in the future, we would ask that you re-add the attribution or sign up for our [Pro membership](https://rv-grid.com/pro).
**Thank you for supporting the RevoGrid team!** ✌🏻
---
# Contributing
Source: https://rv-grid.com/guide/CONTRIBUTING
# Contributing
Thank you for your interest in contributing to RevoGrid! 🎉
## Why Contribute?
Contributing to RevoGrid not only offers developers the chance to enhance their skills and collaborate on cutting-edge data grid technology but also presents a unique opportunity for professional growth and financial gain. By participating in the development of RevoGrid, contributors can directly influence a tool used by companies worldwide, adding significant value to their professional portfolio. Moreover, standout contributors may have the opportunity to join our team full-time or benefit from paid project work, tapping into new career opportunities and monetary rewards. Contributing to RevoGrid is more than just coding—it's a chance to join a community that rewards your expertise and dedication with tangible benefits.
## Contributing Etiquette
Please see our [Contributor Code of Conduct](https://rv-grid.com/guide/CODE_OF_CONDUCT) for information on our rules of conduct.
## Reporting a Bug
* It is required that you clearly describe the steps necessary to reproduce the issue you are encountering. Diagnosing issues without clear reproduction steps is extremely time-consuming and not sustainable.
* The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately.
* Issues with no clear steps to reproduce will not be triaged.
* If you think you have found a bug, please check if it has already been [reported](https://github.com/revolist/revogrid/issues). You can search through existing issues and include closed ones as it may have been resolved.
* If a bug report already exists, please upvote it using the :+1: reaction on the GitHub Issue summary to avoid "+1" comments.
* Next, [create a new issue](https://github.com/revolist/revogrid/issues/new) that thoroughly explains the problem.
* Please fill out the issue form completely before submitting.
* Please only include one bug per issue.
## Requesting a Feature
* Before requesting a feature, check if it has already been [proposed](https://github.com/revolist/revogrid/issues).
* If a feature request already exists, please support it using the :+1: reaction on the GitHub Issue summary.
* Next, [create a new feature request](https://github.com/revolist/revogrid/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=feat%3A+) that thoroughly explains the desired feature.
* Please fill out the feature request form completely before submitting.
* Please only include one feature request per report.
## Creating a Pull Request
* We appreciate your willingness to contribute! Before submitting a pull request, please [create an issue](#reporting-a-bug) discussing the bug or feature request and indicate that you plan to work on it. If an issue already exists, please comment on that issue stating your intention to submit a pull request. This helps us track pull requests and ensure there is no duplicated effort.
### Setup
1. Fork the repo.
2. Clone your fork.
3. Create a branch for your changes.
4. Run `npm install` to install dependencies.
5. Make your changes.
### Making Sure Your Changes Are Ready
1. Add unit tests for any new or changed functionality. Look at existing tests for guidance on how to write tests.
2. Run `npm run build` to ensure your code compiles correctly.
3. Run `npm test` to make sure all tests pass.
### Submitting Your Changes
After you've made sure all tests pass:
1. Push your changes to your fork.
2. Submit a pull request to the RevoGrid repository.
3. Provide a detailed description of your changes and reference the issue number.
### Commit Message Format
We follow the [Angular Commit Message Format](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits):
* **Type**: feat, fix, docs, style, refactor, perf, test, chore, revert.
* **Scope**: The scope could be anything specifying the place of the commit change.
* **Subject**: Brief description of the change.
## License
By contributing to RevoGrid, you agree that your contributions will be licensed under its MIT License.
---
# RevoGrid Migration Guides
Source: https://rv-grid.com/guide/migration
Description: Review RevoGrid version changes and upgrade notes, including migration guidance for v2, v3, and v4 projects.
## Version 4.28.0
### Breaking change: Default filter conditions are now visible
Opening an empty column filter panel now displays one removable draft condition.
String columns start with **Contains**, number columns start with **=**, and other
filter families use their first available operator. The draft does not filter
rows, emit filtering events, or mark the column as filtered until the user
enters a value or explicitly selects an operator.
To preserve the previous empty-panel behavior for the whole grid, disable
default filter drafts in the filter configuration:
```ts
grid.filter = { defaultFilter: false };
```
To disable the draft for only one column, use the structured column filter
configuration:
```ts
grid.columns = [
{
prop: 'name',
filter: { type: 'string', default: false },
},
];
```
See [Filtering](https://rv-grid.com/guide/filters#default-filter-conditions) for column overrides and
the complete draft lifecycle.
## Version 2.0+
- Introduced the plugin system, grouping, sorting, and filtering.
## Version 3.0+
- **Breaking Changes**:
- Removed the redundant viewport component.
- Renamed classes to support Bootstrap and other libraries:
- `row` -> `rgRow`
- `col` -> `rgCol`
- `data-cell` -> `rgCell`
- `data-header-cell` -> `rgHeaderCell`
- Migrated all method names to lowercase to align with modern event naming conventions. For example, `afterEdit` is now `afteredit`. Check the API for details.
- Added support for pure ESM modules to enable the use of the grid in all modern frontend tooling like Vite, Parcel, etc. You can now import custom elements without lazy loading. Note that you are responsible for polyfills.
## Version 4.0+
:::tip
For a comprehensive migration guide check the [migration guide](https://rv-grid.com/guide/migrations/v4).
:::
- **Summary on Breaking Changes**:
- Redesigned type support:
- Removed deprecated namespaces `RevoGrid`, `Selection` and others from type imports. Use direct import instead. For example:
- **Before**: `RevoGrid.ColumnRegular`
- **Now**: `ColumnRegular`;
...
- Improved type imports. For example:
- **Before**: `import { RevoGrid } from '@revolist/revogrid/dist/types/interfaces'`
- **Now**: `import { ColumnRegular } from '@revolist/revogrid'`.
- Changed viewport type names everywhere. For example, before: `rowDefinitions: [{ type: "row", index: 0, size: 145 }]`, after: `rowDefinitions: [{ type: "rgRow", index: 0, size: 145 }]`.
- Updated [event](https://rv-grid.com/guide/api/events) naming convention. Review your [event](https://rv-grid.com/guide/api/events) usage. [Event names](https://rv-grid.com/guide/api/events) are all lowercase now and are aligned with modern event naming conventions. For example, `afterEdit` -> `afteredit`. Check migration guide for details.
- **Major improvements**:
- Rethought the entire framework approach. Introduced [Pro](https://rv-grid.com/pro/) version with advance support and pro features.
- Updated scrolling system for better mobile support.
- Advance template support. Introduced `additionalData` for templates and editors. `Prop` gives access to parent/root app context.
- Redesigned the documentation.
- Fixed major issues and significantly improved overall performance, making the grid multiple time faster.
- Enhanced plugin support - now with full access to grid providers.
- Provided full framework support and native render for [Angular](https://rv-grid.com/guide/angular/), [React](https://rv-grid.com/guide/react/), [Svelte](https://rv-grid.com/guide/svelte/), and [Vue](https://rv-grid.com/guide/vue3/), with partial support for Ember.
---
# Demo React Data Grid and Table
Source: https://rv-grid.com/guide/demos/react/react-datagrid
Description: Try the RevoGrid React data grid demo with virtual rows and columns, editable cells, high-performance rendering, and React integration examples.
# React Data Grid Demo
Use this React demo to start a RevoGrid table with virtualized rows and columns, editable cells, and high-performance rendering for large datasets.
[](https://codesandbox.io/p/sandbox/react-revogrid-start-29fm5z)
---
# React Native Cell component in Data Grid
Source: https://rv-grid.com/guide/demos/react/react.cell
Description: Native cell template rendering in RevoGrid for React Table, allowing the use of custom React components inside grid cells.
# React Custom Cell Template Demo
[](https://codesandbox.io/p/sandbox/react-revogrid-cell-jgt3mv)
### Key Considerations for Custom Cell Templates
- **Data Access**: Each custom cell component will have access to the data for that row via its props. The primary prop that is passed to custom renderers is the value of the cell.
- **Performance**: Custom renderers can impact grid performance, especially with large datasets. RevoGrid optimizes rendering by only updating cells that have changed, but it’s important to keep performance in mind when creating complex cell templates.
- **Conditional Rendering**: You can use conditional logic inside your custom cell component to change its appearance based on the data. For example, you can display different colors or icons based on numeric values or boolean flags.
- **Event Handling**: Custom cells can include event handlers, such as onClick, onChange, etc., to make the grid interactive. This is ideal for rendering editable fields, buttons, or custom controls.
### Advanced Use Cases
RevoGrid’s native rendering support opens up even more complex scenarios where you can render interactive components, such as:
- **Dynamic Dropdowns**: Populate a dropdown inside a cell based on the data in the grid or external sources.
- **Custom Formatting**: Display values with custom formatting, such as currency symbols, percentages, or styled numbers.
- **Inline Editing**: Build advanced inline editing components, such as date pickers, checkboxes, or toggles, inside grid cells.
---
# React Native Editor Data Grid component
Source: https://rv-grid.com/guide/demos/react/react.editor
Description: Learn how to use React for native editor rendering in RevoGrid, allowing custom in-cell editing with React components.
# React Data Grid Cell Editor Demo
RevoGrid allows for even more complex custom editors by passing data and handling events like onChange or onBlur. You can create more interactive editors such as input fields, checkboxes, or dropdowns that allow users to update cell values directly.
[](https://codesandbox.io/p/sandbox/react-revogrid-cell-vdjyp2)
### Advanced Use Cases
You can extend RevoGrid’s native editor rendering by implementing more sophisticated editors, such as:
- **Date Pickers**: Use a date picker React component to edit date values in a column.
- **Select Menus**: Render a dropdown menu with dynamic options based on other grid data or external sources.
- **Multistep Editors**: Create complex multi-field editors for advanced data entry.
---
# React Grouping View Data Grid Table
Source: https://rv-grid.com/guide/demos/react/react-grouping
Description: Group rows in a React RevoGrid data grid with an interactive grouping demo and standalone source example.
# React Row Grouping Data Grid Demo
Group rows in a React data grid with RevoGrid and an interactive row grouping example.
[](https://codesandbox.io/p/sandbox/react-revogrid-grouping-h5f9sh?from-embed=)
---
# React Multi Select Data Grid Table
Source: https://rv-grid.com/guide/demos/react/react-multiselect
Description: Build a React multiselect data grid with RevoGrid, virtual rendering, and an interactive selection demo.
# React Multi Select Data Grid Demo
Use this React demo to render a multiselect data grid with RevoGrid and virtualized selection behavior.
[](https://codesandbox.io/p/sandbox/react-revogrid-multiselect-mgy263)
---
# React Tree Data Grid
Source: https://rv-grid.com/guide/demos/react/react-tree
Description: Explore the free RevoGrid React core tree pattern first, then see how RevoGrid Pro TreeDataPlugin adds expand and collapse controls, sticky parents, and hierarchy-aware behavior.
Start with the free/core tree pattern: flatten parent-child rows into display order, add a `level` field, and render indentation in a React cell template.
[](https://codesandbox.io/p/sandbox/react-revogrid-tree-7mq6cm?from-embed=)
## Pro Tree Data
RevoGrid Pro adds `TreeDataPlugin` when you need built-in expand and collapse controls, hierarchy-aware row visibility, sticky parent rows, row selection integration, row drag integration, filtering, sorting, and virtualization over advanced tree structures.
Use the full [React Tree Data guide](https://rv-grid.com/guide/react/tree) for both approaches and the [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data) for the complete Pro tree model.
---
# Demo Angular Data Grid Standalone
Source: https://rv-grid.com/guide/demos/angular/angular-datagrid
Description: Start a standalone Angular data grid with RevoGrid, virtual scrolling, editable cells, and framework-native integration examples.
# Angular Data Grid Demo
Use this Angular standalone demo to render RevoGrid with virtual scrolling, editable cells, and framework-native setup.
[](https://codesandbox.io/p/sandbox/rg-cell-angular-standalone-t4lrz2)
---
# Native Cell component - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.cell
Description: Render native Angular components inside RevoGrid cells with this Angular data grid cell template demo.
[](https://codesandbox.io/p/sandbox/rg-cell-angular-standalone-t4lrz2)
---
# Column resize - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.column-resize
Description: Resize Angular data grid columns with RevoGrid and combine column sizing with custom cell templates.
[![Edit RG Table column resize & Cell Template [Angular]](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/table-column-resize-and-cell-template)
---
# Header component & Tooltip - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.header
Description: Customize Angular data grid headers and tooltips with RevoGrid header component rendering.
# Header Component and Tooltip Demo
[](https://codesandbox.io/p/sandbox/rg-header-tooltip-angular-standalone-yz77gy)
---
# Native Editor component - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.editor
Description: Build a native Angular cell editor for RevoGrid with this editable data grid demo.
# Native Editor Component Demo
[](https://codesandbox.io/p/sandbox/rg-editor-angular-standalone-lgc3pr)
---
# Native Date Editor - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.editor-custom
Description: Use a custom native Angular date editor inside RevoGrid cells with this standalone Angular demo.
[](https://codesandbox.io/p/sandbox/rg-custom-date-editor-angular-standalone-548j6x)
---
# Focus Catch - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.focus
Description: Capture and handle RevoGrid focus events in an Angular standalone data grid demo.
# Focus Catch Demo
[](https://codesandbox.io/p/sandbox/rg-focus-catch-angular-standalone-3rmdt3)
---
# Inventory Spreadsheet Demo - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.full-demo
Description: Open an Angular inventory spreadsheet demo built with RevoGrid for editable rows, tabular business data, and standalone Angular setup.
# Inventory Spreadsheet Demo
Use this Angular inventory spreadsheet demo to explore editable business data workflows with RevoGrid.
[](https://codesandbox.io/p/sandbox/rg-inventory-list-demo-angular-forked-rzq2jj)
---
# Getting Started Module - Angular Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular.sample.module
Description: Start RevoGrid in an Angular module-based application with this Angular data grid demo.
## Getting Started Module
[](https://codesandbox.io/p/sandbox/rg-start-angular-module-3ls7pr)
---
# Angular Tree Data Grid
Source: https://rv-grid.com/guide/demos/angular/angular-tree
Description: Explore an Angular tree data grid with RevoGrid Pro TreeDataPlugin, flat parent-child rows, expandable hierarchy controls, sticky parents, drag-and-drop, filtering, and virtualized rendering.
Angular can use the free/core tree pattern with a flattened `source` and an indented cell template. The live Angular widget below shows the Pro upgrade path, where the plugin manages tree state and interactions for you.
## Pro Tree Data
Use the full [Angular Tree Data guide](https://rv-grid.com/guide/angular/tree) for both approaches and the [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data) for the complete Pro tree model.
---
# Get Started with Vue 3 Data Grid Demo - Composition API
Source: https://rv-grid.com/guide/demos/vue/vue3-datagrid
Description: Start a Vue 3 Composition API data grid with RevoGrid, virtual scrolling, editable cells, and source code examples.
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue3-datagrid.vue) [Codesandbox](https://codesandbox.io/p/sandbox/rg-start-vue-3-composition-api-3775m4)
::: code-group
<<< @/demo/vue/vue3-datagrid.vue
:::
---
# Get Started with Vue 3 Data Grid Demo - Options API
Source: https://rv-grid.com/guide/demos/vue/vue.sample.options
Description: Start a Vue 3 Options API data grid with RevoGrid, virtual scrolling, editable cells, and source code examples.
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue.cell.composition.example.vue) [Codesandbox](https://codesandbox.io/p/sandbox/rg-cell-vue-3-composition-api-cvv97n)
::: code-group
<<< @/demo/vue/vue.cell.composition.example.vue
<<< @/demo/vue/vue.cell.composition.example-cell.vue
:::
---
# Vue 3 Data Grid Cell Editor component (Composition API)
Source: https://rv-grid.com/guide/demos/vue/vue.editor.composition
Description: Build a Vue 3 Composition API cell editor for RevoGrid with custom editor components and source code.
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/vue/vue.editor.composition.example.vue) [Codesandbox](https://codesandbox.io/p/sandbox/rg-editor-vue-3-composition-api-sl8vvw)
::: code-group
<<< @/demo/vue/vue.editor.composition.example.vue
<<< @/demo/vue/vue.editor.composition.example-editor.vue
:::
---
# Multi Select Virtual List - Vue 3 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue.select
Description: Build a Vue 3 multiselect virtual list with RevoGrid and Composition API source examples.
# Vue 3 - Multi Select (Composition API)
:::tabs
== Preview
== Source code
<<< @/demo/vue/vue.select.vue
== Codesandbox
[](https://codesandbox.io/p/sandbox/rg-select-all-vue-3-composition-api-4myr3l)
:::
---
# Row Grouping - Vue 3 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue.grouping
Description: Group rows in a Vue 3 RevoGrid data grid with a Composition API demo and interactive grouping example.
# Vue 3 - Row Grouping Demo
[](https://codesandbox.io/p/sandbox/rg-start-vue-3-composition-api-forked-ffwdrt?file=%2Fsrc%2FApp.vue%3A19%2C41)
---
# Vue 3 Tree Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue-tree
Description: Explore the free RevoGrid Vue 3 core tree pattern first, then see how RevoGrid Pro TreeDataPlugin adds expand and collapse controls, sticky parents, and hierarchy-aware behavior.
# Vue 3 - Tree Data Grid
Start with the free/core tree pattern: flatten parent-child rows into display order, add a `level` field, and render indentation in a Vue cell template.
## Pro Tree Data
RevoGrid Pro adds `TreeDataPlugin` when you need built-in expand and collapse controls, hierarchy-aware row visibility, sticky parent rows, row selection integration, row drag integration, filtering, sorting, and virtualization over advanced tree structures.
Use the full [Vue 3 Tree Data guide](https://rv-grid.com/guide/vue3/tree) for both approaches and the [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data) for the complete Pro tree model.
---
# Getting Started - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2-datagrid
Description: Start a Vue 2 data grid with RevoGrid using a basic editable grid setup and CodeSandbox example.
[](https://codesandbox.io/p/sandbox/rg-start-vue-2-3zl8hd)
---
# Native Cell component - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.cell
Description: Render native Vue 2 components inside RevoGrid cells with this cell template demo.
# Native Cell Component - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-cell-vue-2-78q5fl)
---
# Native Editor component - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.editor
Description: Build a native Vue 2 editor component for editable RevoGrid cells.
# Native Editor Component - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-editor-vue-2-9zr8ng)
---
# Native Date Editor component - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.date
Description: Use a native Vue 2 date editor with RevoGrid column types and editable grid cells.
# Native Date Editor Component - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-date-column-localization-vue-2-nnd8w3)
---
# Grouping - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.grouping
Description: Group rows in a Vue 2 data grid with RevoGrid and a focused row grouping demo.
[](https://codesandbox.io/p/sandbox/rg-grouping-vue-2-2m3lzc)
---
# Multiselect Virtual list - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.list
Description: Render a virtual multiselect list in Vue 2 with RevoGrid for large selectable datasets.
# Multiselect Virtual List - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-infinity-list-vue-2-options-api-wgd96l)
---
# Multi Select Data Grid Virtual list - Vue 2 Data Grid
Source: https://rv-grid.com/guide/demos/vue/vue2.select
Description: Build a Vue 2 RevoGrid select-all list with virtual rendering and multiselect behavior.
# Multi Select Data Grid Virtual List - Vue 2 Data Grid
[](https://codesandbox.io/p/sandbox/rg-select-all-list-vue-2-options-api-rr25l9)
---
# Demo JavaScript Data Grid
Source: https://rv-grid.com/guide/demos/js/js.overview
Description: Try a standalone JavaScript data grid demo with RevoGrid, virtual scrolling, editable data, and source code for browser-based setup.
# JavaScript Data Grid Demo
Use this standalone JavaScript demo to see RevoGrid render editable tabular data with virtual scrolling and fast browser performance.
:::preview #demo-overview .rv-overview :path /demo/js/js.overview.example
:::
::: details Source code [Git](https://github.com/revolist/revogrid-docs/tree/main/demo/js/js.overview.example.ts) [Codesandbox](https://codesandbox.io/p/sandbox/rg-quick-overview-88rf36?from-embed=)
::: code-group
<<< @/demo/js/js.overview.example.ts#snippet
<<< @/json/stock.json
:::
---
# Row Grouping in Data Grid
Source: https://rv-grid.com/guide/demos/js/js.grouping
Description: Learn how to configure row grouping in RevoGrid using TypeScript. Easily group rows based on specific properties for better data organization and visualization.
[Interface: GroupingOptions](https://rv-grid.com/guide/types/TypeAlias.GroupingOptions)
Row grouping in RevoGrid allows you to organize rows based on a specific property, making it easy to categorize and visualize hierarchical data. With RevoGrid’s powerful features, you can set up grouping with minimal configuration.
[](https://codesandbox.io/p/sandbox/rg-start-standalone-forked-xkr9wq)
---
# Individual row sizes
Source: https://rv-grid.com/guide/demos/js/js.custom.rows
Description: Configure individual RevoGrid row sizes in a standalone JavaScript data grid demo.
# Individual Row Sizes Demo
[](https://codesandbox.io/p/sandbox/rg-quick-overview-forked-yc77yn?file=%2Fsrc%2Findex.ts%3A22%2C13)
---
# Date column
Source: https://rv-grid.com/guide/demos/js/js.date
Description: Add a date column to a standalone RevoGrid JavaScript data grid with date editor behavior.
# Date Column Demo
[](https://codesandbox.io/p/sandbox/rg-date-standalone-jwwwd8?file=%2Fsrc%2Findex.ts%3A27%2C62)
---
# Filter Plugin
Source: https://rv-grid.com/guide/demos/js/js.filtering
Description: Configure RevoGrid filtering in a standalone JavaScript data grid demo with clear filter behavior.
# Filter Plugin Demo
[](https://codesandbox.io/p/sandbox/rg-filtering-defined-z9mzgr)
---
# JSX and TSX Data Grid Template Demo
Source: https://rv-grid.com/guide/demos/jsx/jsx.template
Description: Render custom RevoGrid cell content with JSX and TSX templates in a TypeScript data grid demo.
# JSX/TSX - DataGrid Template Demo
## TypeScript JSX Cell Template Demo
[Check out this sample.](https://codesandbox.io/s/revo-grid-vanilla-jsx-zj0q6?file=/src/index.js)
We use babel-jsx with minimal configuration settings.
---
# TypeScript Tree Data Grid
Source: https://rv-grid.com/guide/demos/jsx/jsx-tree
Description: Explore the free RevoGrid TypeScript core tree pattern first, then see how RevoGrid Pro TreeDataPlugin adds expand and collapse controls, sticky parents, and hierarchy-aware behavior.
Start with the free/core tree pattern: flatten parent-child rows into display order, add a `level` field, and render indentation in a cell template.
## Pro Tree Data
RevoGrid Pro adds `TreeDataPlugin` when you need built-in expand and collapse controls, hierarchy-aware row visibility, sticky parent rows, row selection integration, row drag integration, filtering, sorting, and virtualization over advanced tree structures.
Use the full [TypeScript Tree Data guide](https://rv-grid.com/guide/ts/tree) for both approaches and the [Advanced Tree Data guide](https://rv-grid.com/guide/tree-data) for the complete Pro tree model.
---
# JavaScript Data Grid Demo for Large Datasets
Source: https://rv-grid.com/demo
Description: Test RevoGrid with a large editable dataset, virtual scrolling, filtering, sorting, and framework-ready JavaScript data grid interactions.
---
# AI Prompt Library Data Grid Demo
Source: https://rv-grid.com/demo/ai-prompts
Description: Explore a searchable, filterable, and editable AI prompt catalog with multiline content and instant local data loading in the open-source Core grid.
---
# Project Portfolio Row Grouping Demo
Source: https://rv-grid.com/demo/project-portfolio
Description: Explore a realistic project portfolio with two-level row grouping, custom progress cells, sorting, and filtering in the open-source Core grid.
---
# Tree Data Grid Hierarchy Demo
Source: https://rv-grid.com/demo/tree-data
Description: Explore expandable hierarchical data grid rows with sticky parents, animated transitions, drag ordering, filters, selection, and export.
---
# Advanced Data Grid Filtering Demo
Source: https://rv-grid.com/demo/filtering
Description: Combine filter presets, global search, expressions, selection cascades, date rules, and numeric sliders in the RevoGrid Pro filtering demo.
---
# Infinity Scroll Data Grid Demo
Source: https://rv-grid.com/demo/infinity-scroll
Description: Load remote data grid rows in buffered chunks with server-side sorting, filtering, pinned summaries, and Excel export in RevoGrid Pro.
---
# Column Collapse Data Grid Demo
Source: https://rv-grid.com/demo/column-collapse
Description: Collapse grouped data grid columns into sealed summary fields, then expand, filter, resize, and select rows in this RevoGrid Pro demo.
---
# Context Menu & Cell Formatting Demo
Source: https://rv-grid.com/demo/context-menu
Description: Open selection-aware menus for cells, rows, columns, and grouped headers, then apply rich cell formatting in this RevoGrid Pro data grid demo.
---
# Row Master Detail Data Grid Demo
Source: https://rv-grid.com/demo/row-master
Description: Expand hierarchical project rows into rich master-detail panels with asynchronous content and virtualized grid navigation in RevoGrid Pro.
---
# Audit History Data Grid Demo
Source: https://rv-grid.com/demo/audit-history
Description: Track attributed data grid edits, compare revisions, export audit records, and restore earlier cell values in the RevoGrid Pro audit history demo.
---
# Project Tracker Data Grid Demo
Source: https://rv-grid.com/demo/color
Description: Edit projects, owners, priorities, statuses, and deadlines in a color-coded RevoGrid Pro project tracker with filtering and drag ordering.
---
# Grid, Kanban, Gantt Charts & Event Scheduler Demo
Source: https://rv-grid.com/demo/planning
Description: Edit one shared task model across synchronized Data Grid, Kanban, Gantt, Scheduler, and Calendar views in RevoGrid Pro Advanced.
---
# Large Dataset Gantt Demo
Source: https://rv-grid.com/demo/gantt-big-data
Description: Explore 10,000 virtualized Gantt tasks and 19,796 dependencies across a three-month project while keeping timeline rendering responsive.
---
# 20Y-Timeline Gantt Demo
Source: https://rv-grid.com/demo/gantt-horizontal-big-data
Description: Explore 100 linked tasks across a twenty-year Gantt timeline with month-and-quarter scaling and responsive horizontal rendering.
---
# JavaScript Scheduler and Shift Planning Demo
Source: https://rv-grid.com/demo/event-scheduler
Description: Schedule employee shifts and resources with RevoGrid Pro Advanced using calendar views, conflict detection, and drag-to-create, move, or resize.
---
# 50K-Task JavaScript Kanban Demo | RevoGrid Kanban
Source: https://rv-grid.com/demo/kanban-performance
Description: Explore 50,000 virtualized tasks in RevoGrid Kanban across ten workflow columns and two team swimlanes.
---
# 100K JavaScript Kanban Demo | RevoGrid Kanban
Source: https://rv-grid.com/demo/kanban-server-loading
Description: Page through 100,000 remote cards in RevoGrid Kanban with virtualized loading, accurate totals, and request status.
---
# JavaScript Pivot Table Component Demo
Source: https://rv-grid.com/demo/pivot
Description: Try the RevoGrid JavaScript pivot table component with drag-and-drop fields, aggregation, filtering, drill-down, grouped axes, totals, and export.