Excel Export
RevoGrid Pro exports grid data to .xlsx workbooks through ExportExcelPlugin. The same plugin also keeps the historical CSV drag-and-drop import path, so existing integrations can keep using the ExportExcelPlugin, grid.exportExcel, and export-excel event names.
Source code
TypeScript ts
// src/components/export-excel/ExportExcel.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();
import { currentTheme, useRandomData } from '../composables/useRandomData';
import './export-excel.scss';
import {
EXCEL_DEMO_ROW_COUNT,
applyExcelDemoGridSettings,
createDefaultExcelDemoExportOptions,
createDefaultExcelDemoGridOptions,
createExcelDemoCellMerge,
createExcelDemoColumnTypes,
createExcelDemoColumns,
createExcelDemoExportConfig,
createExcelDemoPinnedBottomSource,
createExcelDemoPinnedTopSource,
createExcelDemoRows,
type ExcelDemoExportOptions,
type ExcelDemoGridOptions,
} from './export-excel-demo-options';
import {
EXCEL_DEMO_EXPORT_EVENT,
EXCEL_DEMO_OPTIONS_CHANGE_EVENT,
createExcelDemoToolbar,
type ExcelDemoExportEvent,
type ExcelDemoOptionsChangeEvent,
} from './export-excel-demo-toolbar';
const { createRandomData } = useRandomData();
const { isDark } = currentTheme();
import {
ColumnStretchPlugin,
CellMergePlugin,
ExportExcelPlugin,
FormulaPlugin,
RowOddPlugin,
} from '@revolist/revogrid-pro';
export function load(parentSelector: string) {
const parent = document.querySelector(parentSelector);
if (!parent) {
return;
}
const container = document.createElement('div');
container.className = `export-excel-demo grow ${gridOptionsClass(isDark())}`;
let exportOptions = createDefaultExcelDemoExportOptions();
let gridOptions = createDefaultExcelDemoGridOptions(isDark());
const mergeRenderedGridOptions = (
options: { exportOptions: ExcelDemoExportOptions; gridOptions: ExcelDemoGridOptions },
) => ({
...options.gridOptions,
...options.exportOptions,
});
const toolbar = createExcelDemoToolbar({ exportOptions, gridOptions });
const grid = document.createElement('revo-grid');
grid.className = 'export-excel-grid cell-border';
grid.columns = createExcelDemoColumns(gridOptions);
grid.columnTypes = createExcelDemoColumnTypes();
grid.cellMerge = createExcelDemoCellMerge(gridOptions);
grid.pinnedTopSource = createExcelDemoPinnedTopSource(gridOptions);
grid.pinnedBottomSource = createExcelDemoPinnedBottomSource(gridOptions);
grid.stretch = 'all';
// Define plugin
grid.plugins = [ExportExcelPlugin, FormulaPlugin, RowOddPlugin, ColumnStretchPlugin, CellMergePlugin];
toolbar.addEventListener(EXCEL_DEMO_OPTIONS_CHANGE_EVENT, (event) => {
({ exportOptions, gridOptions } = (event as ExcelDemoOptionsChangeEvent).detail);
container.classList.toggle('is-dark', gridOptions.theme === 'darkMaterial');
applyExcelDemoGridSettings(grid, mergeRenderedGridOptions({ exportOptions, gridOptions }));
});
toolbar.addEventListener(EXCEL_DEMO_EXPORT_EVENT, async (event) => {
({ exportOptions, gridOptions } = (event as ExcelDemoExportEvent).detail);
toolbar.exporting = true;
try {
const plugins = await grid.getPlugins();
const plugin = plugins.find(p => p instanceof ExportExcelPlugin) as ExportExcelPlugin;
await plugin?.export(createExcelDemoExportConfig(exportOptions));
} finally {
toolbar.exporting = false;
}
// Or dispatch the public event with the same provider options.
// dispatch(grid, 'export-excel', createExcelDemoExportConfig(exportOptions));
});
grid.theme = gridOptions.theme;
grid.hideAttribution = true;
applyExcelDemoGridSettings(grid, mergeRenderedGridOptions({ exportOptions, gridOptions }));
container.append(toolbar, grid);
parent.appendChild(container);
grid.source = createExcelDemoRows(createRandomData(EXCEL_DEMO_ROW_COUNT));
return () => container.remove();
}
function gridOptionsClass(isDarkTheme: boolean) {
return isDarkTheme ? 'is-dark' : '';
}
Vue vue
// src/components/export/ExportExcel.vue
<template>
<div :class="['export-excel-demo', { 'is-dark': gridOptions.theme === 'darkMaterial' }]">
<export-excel-demo-toolbar
ref="toolbar"
@excel-demo-options-change="updateToolbarOptions"
@excel-demo-export="exportToExcel"
/>
<VGrid
ref="grid"
class="export-excel-grid cell-border"
:theme="gridOptions.theme"
:columns="columns"
:column-types="columnTypes"
:cell-merge.prop="cellMerge"
:source="rows"
:plugins="plugins"
stretch="all"
:pinned-top-source="pinnedTopSource"
:pinned-bottom-source="pinnedBottomSource"
hide-attribution
/>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { currentThemeVue, useRandomData } from '../composables/useRandomData'
import { VGrid } from '@revolist/vue3-datagrid'
import { ExportExcelPlugin, ColumnStretchPlugin, FormulaPlugin, RowOddPlugin, CellMergePlugin } from '@revolist/revogrid-pro'
import './export-excel.scss'
import {
EXCEL_DEMO_ROW_COUNT,
applyExcelDemoGridSettings,
createDefaultExcelDemoExportOptions,
createDefaultExcelDemoGridOptions,
createExcelDemoCellMerge,
createExcelDemoColumnTypes,
createExcelDemoColumns,
createExcelDemoExportConfig,
createExcelDemoPinnedBottomSource,
createExcelDemoPinnedTopSource,
createExcelDemoRows,
} from './export-excel-demo-options'
import {
defineExcelDemoToolbarElement,
type ExcelDemoExportEvent,
type ExcelDemoOptionsChangeEvent,
type ExcelDemoToolbarElement,
} from './export-excel-demo-toolbar'
defineExcelDemoToolbarElement()
const { createRandomData } = useRandomData()
const { isDark } = currentThemeVue()
const grid = ref<{ $el: HTMLRevoGridElement } | null>(null);
const toolbar = ref<ExcelDemoToolbarElement | null>(null);
const exporting = ref(false)
const exportOptions = reactive(createDefaultExcelDemoExportOptions())
const gridOptions = reactive(createDefaultExcelDemoGridOptions(isDark.value))
const renderedGridOptions = computed(() => ({ ...gridOptions, ...exportOptions }))
const columns = computed(() => createExcelDemoColumns(renderedGridOptions.value))
const cellMerge = computed(() => createExcelDemoCellMerge(renderedGridOptions.value))
const columnTypes = createExcelDemoColumnTypes()
const plugins = [ExportExcelPlugin, ColumnStretchPlugin, FormulaPlugin, RowOddPlugin, CellMergePlugin]
const rows = ref(createExcelDemoRows(createRandomData(EXCEL_DEMO_ROW_COUNT)))
const pinnedTopSource = computed(() => createExcelDemoPinnedTopSource(renderedGridOptions.value))
const pinnedBottomSource = computed(() => createExcelDemoPinnedBottomSource(renderedGridOptions.value))
const syncRenderedGridSettings = () => {
if (grid.value) {
applyExcelDemoGridSettings(grid.value.$el, renderedGridOptions.value)
}
}
const syncToolbar = () => {
if (toolbar.value) {
toolbar.value.options = {
exportOptions: { ...exportOptions },
gridOptions: { ...gridOptions },
}
toolbar.value.exporting = exporting.value
}
}
onMounted(() => {
syncRenderedGridSettings()
syncToolbar()
})
watch(renderedGridOptions, () => {
syncRenderedGridSettings()
syncToolbar()
}, { flush: 'post' })
watch(exporting, syncToolbar)
const updateToolbarOptions = (event: ExcelDemoOptionsChangeEvent) => {
Object.assign(exportOptions, event.detail.exportOptions)
Object.assign(gridOptions, event.detail.gridOptions)
}
const exportToExcel = async (event: ExcelDemoExportEvent) => {
if (grid.value) {
try {
exporting.value = true
const plugins = await grid.value.$el.getPlugins()
const exportPlugin = plugins.find(
(plugin) => plugin instanceof ExportExcelPlugin
) as ExportExcelPlugin
await exportPlugin?.export(createExcelDemoExportConfig(event.detail.exportOptions))
} finally {
exporting.value = false
}
}
}
</script>
React tsx
// src/components/export/ExportExcel.tsx
import React, { useEffect, useState, useMemo, useRef } from 'react';
import { RevoGrid, type DataType } from '@revolist/react-datagrid';
import {
CellMergePlugin,
ColumnStretchPlugin,
ExportExcelPlugin,
FormulaPlugin,
RowOddPlugin,
} from '@revolist/revogrid-pro';
import { useRandomData, currentTheme } from '../composables/useRandomData';
import './export-excel.scss';
import {
EXCEL_DEMO_ROW_COUNT,
applyExcelDemoGridSettings,
createDefaultExcelDemoExportOptions,
createDefaultExcelDemoGridOptions,
createExcelDemoCellMerge,
createExcelDemoColumnTypes,
createExcelDemoColumns,
createExcelDemoExportConfig,
createExcelDemoPinnedBottomSource,
createExcelDemoPinnedTopSource,
createExcelDemoRows,
type ExcelDemoExportOptions,
type ExcelDemoGridOptions,
} from './export-excel-demo-options';
import {
EXCEL_DEMO_EXPORT_EVENT,
EXCEL_DEMO_OPTIONS_CHANGE_EVENT,
EXCEL_DEMO_TOOLBAR_TAG,
defineExcelDemoToolbarElement,
type ExcelDemoExportEvent,
type ExcelDemoOptionsChangeEvent,
type ExcelDemoToolbarElement,
} from './export-excel-demo-toolbar';
const { isDark } = currentTheme();
const { createRandomData } = useRandomData();
function ExportExcel() {
const gridRef = useRef<HTMLRevoGridElement>(null);
const toolbarRef = useRef<ExcelDemoToolbarElement>(null);
const [source] = useState<DataType[]>(
() => createExcelDemoRows(createRandomData(EXCEL_DEMO_ROW_COUNT)),
);
const [exportOptions, setExportOptions] = useState<ExcelDemoExportOptions>(() =>
createDefaultExcelDemoExportOptions()
);
const [gridOptions, setGridOptions] = useState<ExcelDemoGridOptions>(() =>
createDefaultExcelDemoGridOptions(isDark())
);
const [exporting, setExporting] = useState(false);
const renderedGridOptions = useMemo(
() => ({ ...gridOptions, ...exportOptions }),
[exportOptions, gridOptions],
);
const columns = useMemo(() => createExcelDemoColumns(renderedGridOptions), [renderedGridOptions]);
const cellMerge = useMemo(() => createExcelDemoCellMerge(renderedGridOptions), [renderedGridOptions]);
const columnTypes = useMemo(() => createExcelDemoColumnTypes(), []);
const pinnedTopSource = useMemo(
() => createExcelDemoPinnedTopSource(renderedGridOptions),
[renderedGridOptions],
);
const pinnedBottomSource = useMemo(
() => createExcelDemoPinnedBottomSource(renderedGridOptions),
[renderedGridOptions],
);
const plugins = useMemo(
() => [ExportExcelPlugin, FormulaPlugin, RowOddPlugin, ColumnStretchPlugin, CellMergePlugin],
[],
);
useEffect(() => {
if (gridRef.current) {
applyExcelDemoGridSettings(gridRef.current, renderedGridOptions);
}
}, [renderedGridOptions]);
useEffect(() => {
defineExcelDemoToolbarElement();
}, []);
useEffect(() => {
if (toolbarRef.current) {
toolbarRef.current.options = { exportOptions, gridOptions };
}
}, [exportOptions, gridOptions]);
useEffect(() => {
if (toolbarRef.current) {
toolbarRef.current.exporting = exporting;
}
}, [exporting]);
useEffect(() => {
const toolbar = toolbarRef.current;
if (!toolbar) {
return;
}
const handleOptionsChange = (event: Event) => {
const { exportOptions: nextExportOptions, gridOptions: nextGridOptions } = (
event as ExcelDemoOptionsChangeEvent
).detail;
setExportOptions(nextExportOptions);
setGridOptions(nextGridOptions);
};
const handleExport = (event: Event) => {
void exportToExcel((event as ExcelDemoExportEvent).detail.exportOptions);
};
toolbar.addEventListener(EXCEL_DEMO_OPTIONS_CHANGE_EVENT, handleOptionsChange);
toolbar.addEventListener(EXCEL_DEMO_EXPORT_EVENT, handleExport);
return () => {
toolbar.removeEventListener(EXCEL_DEMO_OPTIONS_CHANGE_EVENT, handleOptionsChange);
toolbar.removeEventListener(EXCEL_DEMO_EXPORT_EVENT, handleExport);
};
}, []);
const exportToExcel = async (options: ExcelDemoExportOptions) => {
const grid = gridRef.current;
if (grid) {
try {
setExporting(true);
const gridPlugins = await grid.getPlugins();
const exportPlugin = gridPlugins.find(
(plugin) => plugin instanceof ExportExcelPlugin
) as ExportExcelPlugin;
await exportPlugin?.export(createExcelDemoExportConfig(options));
} finally {
setExporting(false);
}
}
};
return (
<div className={`export-excel-demo ${gridOptions.theme === 'darkMaterial' ? 'is-dark' : ''}`}>
{React.createElement(EXCEL_DEMO_TOOLBAR_TAG, { ref: toolbarRef })}
<RevoGrid
ref={gridRef}
columns={columns}
columnTypes={columnTypes}
cellMerge={cellMerge}
source={source}
pinnedTopSource={pinnedTopSource}
pinnedBottomSource={pinnedBottomSource}
hide-attribution
theme={gridOptions.theme}
plugins={plugins}
className="export-excel-grid cell-border"
stretch="all"
/>
</div>
);
}
export default ExportExcel;
Angular ts
// src/components/export-excel/ExportExcelAngular.ts
import {
AfterViewInit,
CUSTOM_ELEMENTS_SCHEMA,
Component,
ElementRef,
ViewEncapsulation,
ViewChild,
} from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import {
CellMergePlugin,
ColumnStretchPlugin,
ExportExcelPlugin,
FormulaPlugin,
RowOddPlugin,
} from '@revolist/revogrid-pro';
import { useRandomData, currentTheme } from '../composables/useRandomData';
import {
EXCEL_DEMO_ROW_COUNT,
applyExcelDemoGridSettings,
createDefaultExcelDemoExportOptions,
createDefaultExcelDemoGridOptions,
createExcelDemoCellMerge,
createExcelDemoColumnTypes,
createExcelDemoColumns,
createExcelDemoExportConfig,
createExcelDemoPinnedBottomSource,
createExcelDemoPinnedTopSource,
createExcelDemoRows,
type ExcelDemoExportOptions,
type ExcelDemoGridOptions,
} from './export-excel-demo-options';
import {
defineExcelDemoToolbarElement,
type ExcelDemoExportEvent,
type ExcelDemoOptionsChangeEvent,
type ExcelDemoToolbarElement,
} from './export-excel-demo-toolbar';
defineExcelDemoToolbarElement();
@Component({
selector: 'export-excel-grid',
standalone: true,
imports: [RevoGrid],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<div class="export-excel-demo" [class.is-dark]="gridOptions.theme === 'darkMaterial'">
<export-excel-demo-toolbar
#toolbarRef
(excel-demo-options-change)="setToolbarOptions($event)"
(excel-demo-export)="exportExcel($event)"
></export-excel-demo-toolbar>
<revo-grid
#gridRef
[columns]="columns"
[columnTypes]="columnTypes"
[cellMerge]="cellMerge"
[source]="source"
[pinnedTopSource]="pinnedTopSource"
[pinnedBottomSource]="pinnedBottomSource"
[hideAttribution]="true"
[theme]="gridOptions.theme"
[plugins]="plugins"
[stretch]="'all'"
class="export-excel-grid cell-border"
></revo-grid>
</div>`,
styleUrls: ['./export-excel.scss'],
encapsulation: ViewEncapsulation.None,
})
export class ExportExcelGridComponent implements AfterViewInit {
@ViewChild('gridRef', { static: true })
gridRef!: HTMLRevoGridElement;
@ViewChild('toolbarRef', { static: true, read: ElementRef })
toolbarRef!: ElementRef<ExcelDemoToolbarElement>;
readonly source = createExcelDemoRows(
useRandomData().createRandomData(EXCEL_DEMO_ROW_COUNT),
);
exportOptions = createDefaultExcelDemoExportOptions();
gridOptions = createDefaultExcelDemoGridOptions(currentTheme().isDark());
columns = createExcelDemoColumns(this.gridOptions);
cellMerge = createExcelDemoCellMerge(this.gridOptions);
columnTypes = createExcelDemoColumnTypes();
pinnedTopSource = createExcelDemoPinnedTopSource(this.gridOptions);
pinnedBottomSource = createExcelDemoPinnedBottomSource(this.gridOptions);
exporting = false;
plugins = [ExportExcelPlugin, FormulaPlugin, RowOddPlugin, ColumnStretchPlugin, CellMergePlugin];
private get renderedGridOptions() {
return {
...this.gridOptions,
...this.exportOptions,
};
}
setToolbarOptions(event: ExcelDemoOptionsChangeEvent) {
this.exportOptions = event.detail.exportOptions;
this.gridOptions = event.detail.gridOptions;
this.updateGridDerivedSettings();
}
updateGridDerivedSettings() {
this.columns = createExcelDemoColumns(this.gridOptions);
this.cellMerge = createExcelDemoCellMerge(this.gridOptions);
this.pinnedTopSource = createExcelDemoPinnedTopSource(this.gridOptions);
this.pinnedBottomSource = createExcelDemoPinnedBottomSource(this.gridOptions);
this.updateRenderedGridSettings();
}
updateRenderedGridSettings() {
if (this.gridRef) {
applyExcelDemoGridSettings(this.gridRef, this.renderedGridOptions);
}
}
updateToolbarSettings() {
if (this.toolbarRef) {
this.toolbarRef.nativeElement.options = {
exportOptions: this.exportOptions,
gridOptions: this.gridOptions,
};
this.toolbarRef.nativeElement.exporting = this.exporting;
}
}
ngAfterViewInit() {
this.updateRenderedGridSettings();
this.updateToolbarSettings();
}
async exportExcel(event: ExcelDemoExportEvent) {
try {
this.exporting = true;
this.updateToolbarSettings();
const plugins = await this.gridRef?.getPlugins();
const plugin = plugins.find(
(p) => p instanceof ExportExcelPlugin,
) as ExportExcelPlugin;
await plugin?.export(createExcelDemoExportConfig(event.detail.exportOptions));
} finally {
this.exporting = false;
this.updateToolbarSettings();
}
// Alternatively, dispatch event
// dispatch(grid, 'export-excel', createExcelDemoExportConfig(this.exportOptions));
}
}
Quick Setup
Section titled “Quick Setup”Attach ExportExcelPlugin with your grid plugins:
import { ExportExcelPlugin } from '@revolist/revogrid-pro';
grid.plugins = [ExportExcelPlugin];Trigger export through the event API:
grid.dispatchEvent(new CustomEvent('export-excel', { detail: { workbookName: 'orders.xlsx', sheetName: 'Orders', },}));Or call the plugin instance directly:
const plugins = await grid.getPlugins();const excel = plugins.find((plugin) => plugin instanceof ExportExcelPlugin);
await excel?.export({ workbookName: 'orders.xlsx', sheetName: 'Orders',});Default Behavior
Section titled “Default Behavior”- The bundled provider is
write-excel-fileand exports.xlsxfiles only. - Extensionless
workbookNamevalues receive.xlsx. sheetNameis normalized for Excel worksheet rules.- Export reads grid data stores, not rendered DOM rows, so virtualized offscreen rows are included.
- Row order is pinned top rows, body rows, then pinned bottom rows.
- Columns follow
providers.column.getColumns('all'). - Grid-derived widths and freeze panes are inferred by default from column sizes,
colPinStartcolumns, and pinned-top rows.
Focused Guides
Section titled “Focused Guides”- Export Providers explains provider precedence, default
.xlsxlimits,providerOptions,deriveGridOptions, optional ExcelJS and SheetJS adapters, workbook-module adapters, and custom providers. - Cell Formatting explains
column.excelExport, formula/date/numeral/select helpers, grouped headers, cell merge export support, and the provider context matrix. - CSV Import explains CSV-only drag/drop import,
allowDrag,allowedExtensions,skipColumnGeneration, events, and plugin import helpers. - Migrating to v2.0 explains the SheetJS removal, CSV-only default import, app-owned XLSX import, and provider migration paths as a breaking change from
2.0.8.
Related Export Guides
Section titled “Related Export Guides”- Excel Import and Export Libraries compares SheetJS, ExcelJS, read-excel-file, and write-excel-file for app-owned workbook workflows.
- Gantt Grid, Export, Rendering covers Gantt task-row export mapping and reporting recipes.
- Pivot Export And State covers Pivot CSV, TSV, and state JSON helpers.
- Export Excel API is the generated API reference for the complete public type surface.