Excel Import and Export Libraries
RevoGrid Pro includes an Excel export plugin, but most production apps still need to choose how uploaded workbook files are parsed, validated, normalized, and streamed into the grid.
Use this guide when your workflow is:
- User uploads an Excel file.
- Your app parses
.xlsxdata. - Your app converts the first sheet, selected sheet, or validated sheet into JSON.
- RevoGrid receives normalized
columnsandsourcedata.
Quick Recommendation
Section titled “Quick Recommendation”| Goal | Recommended library | Why |
|---|---|---|
Fast .xlsx upload to grid JSON | SheetJS | Broad format support, direct sheet_to_json() conversion, strong compatibility with real-world workbooks. |
| Full workbook editing or styled report generation | ExcelJS | Good API for worksheets, rows, formatting, formulas, tables, merged cells, and generated reports. |
| Simple validated upload forms | read-excel-file | Small API surface with schema-based parsing and validation. |
Default RevoGrid Pro .xlsx export | write-excel-file | Lightweight writer used by the bundled export provider. |
| Huge browser imports | SheetJS or read-excel-file in a Web Worker | Keep parse work away from the UI thread and load rows into RevoGrid incrementally. |
| Backend import/export processing | SheetJS or ExcelJS | Pick SheetJS for broad import compatibility; pick ExcelJS when workbook editing and formatting matter more. |
SheetJS
Section titled “SheetJS”SheetJS is the strongest general-purpose choice for Excel upload workflows. It works in the browser and Node.js, reads workbook bytes from an ArrayBuffer, supports common spreadsheet formats, and converts worksheets directly into JSON.
Use it when the import goal is “Excel file in, JSON rows out”.
pnpm add xlsximport * as XLSX from 'xlsx';import type { ColumnRegular, DataType } from '@revolist/revogrid';
export async function parseSheetJsFile(file: File): Promise<{ columns: ColumnRegular[]; rows: DataType[];}> { const data = await file.arrayBuffer(); const workbook = XLSX.read(data, { cellDates: true }); const worksheet = workbook.Sheets[workbook.SheetNames[0]]; const rows = XLSX.utils.sheet_to_json<Record<string, unknown>>(worksheet, { defval: '', });
const columns = Object.keys(rows[0] ?? {}).map((key) => ({ prop: key, name: key, }));
return { columns, rows };}const { columns, rows } = await parseSheetJsFile(file);
grid.columns = columns;grid.source = rows;SheetJS is usually the best RevoGrid import fit for admin panels, ERP screens, analytics tools, and customer-provided enterprise spreadsheets where file shape is not perfectly controlled.
The tradeoff is that parsing large files on the main browser thread can freeze the UI. For large files, parse in a Web Worker and only send normalized data back to the page.
import * as XLSX from 'xlsx';
self.onmessage = async (event: MessageEvent<File>) => { const workbook = XLSX.read(await event.data.arrayBuffer(), { cellDates: true }); const worksheet = workbook.Sheets[workbook.SheetNames[0]]; const rows = XLSX.utils.sheet_to_json<Record<string, unknown>>(worksheet, { defval: '', }); const columns = Object.keys(rows[0] ?? {}).map((key) => ({ prop: key, name: key, }));
self.postMessage({ columns, rows });};const worker = new Worker(new URL('./xlsx-import.worker.ts', import.meta.url), { type: 'module',});
worker.onmessage = ({ data }) => { grid.columns = data.columns; grid.source = data.rows;};
worker.postMessage(file);ExcelJS
Section titled “ExcelJS”ExcelJS is better when you need to read, edit, preserve, or generate richer workbook structures. It is a good fit for financial reports, styled exports, workbook templates, formulas, tables, and merged-cell workflows.
Use it when the app needs workbook manipulation, not only raw import speed.
pnpm add exceljsimport ExcelJS from 'exceljs';import type { ColumnRegular, DataType } from '@revolist/revogrid';
export async function parseExcelJsFile(file: File): Promise<{ columns: ColumnRegular[]; rows: DataType[];}> { const workbook = new ExcelJS.Workbook(); await workbook.xlsx.load(await file.arrayBuffer());
const worksheet = workbook.worksheets[0]; const headerRow = worksheet.getRow(1); const headerValues = Array.isArray(headerRow.values) ? headerRow.values.slice(1) : Object.values(headerRow.values); const headers = headerValues .map((value) => String(value ?? '').trim()) .filter(Boolean);
const columns = headers.map((header) => ({ prop: header, name: header, }));
const rows: DataType[] = []; worksheet.eachRow((row, rowNumber) => { if (rowNumber === 1) { return; }
const model: DataType = {}; headers.forEach((header, index) => { model[header] = row.getCell(index + 1).value ?? ''; }); rows.push(model); });
return { columns, rows };}ExcelJS can also be used as an optional RevoGrid export provider when you need workbook features beyond the bundled provider.
import ExcelJS from 'exceljs';import { createExcelJsExcelExportProvider } from '@revolist/revogrid-pro';
grid.exportExcel = { exportProvider: createExcelJsExcelExportProvider(ExcelJS),};The tradeoff is size and speed. ExcelJS is usually heavier than SheetJS for pure “parse and convert to JSON” imports.
read-excel-file
Section titled “read-excel-file”read-excel-file is the best fit when uploads are simple and validation matters more than workbook feature coverage. It reads .xlsx files in the browser or Node.js and can map columns into typed JSON with a schema.
pnpm add read-excel-fileimport readXlsxFile from 'read-excel-file';
const schema = { name: { column: 'Name', type: String, required: true, }, age: { column: 'Age', type: Number, },};
const { rows, errors } = await readXlsxFile(file, { schema });
if (errors.length) { throw new Error(`Invalid spreadsheet: ${errors[0].error}`);}
grid.columns = [ { prop: 'name', name: 'Name' }, { prop: 'age', name: 'Age' },];grid.source = rows;This is a strong choice for import forms, onboarding flows, and ETL-style screens where the workbook is really a typed table.
The tradeoff is that it is not intended to be a full workbook manipulation layer. If users upload complex workbooks with formulas, styles, merged headers, comments, or multiple business sheets, use SheetJS or ExcelJS instead.
write-excel-file
Section titled “write-excel-file”write-excel-file is a lightweight .xlsx writer for browser and Node.js. It is also the default writer behind RevoGrid Pro’s bundled Excel export provider.
For most RevoGrid exports, use ExportExcelPlugin directly:
import { ExportExcelPlugin } from '@revolist/revogrid-pro';
grid.plugins = [ExportExcelPlugin];
const plugins = await grid.getPlugins();await plugins.find((plugin) => plugin instanceof ExportExcelPlugin)?.export({ workbookName: 'orders.xlsx', sheetName: 'Orders',});Use write-excel-file directly when you are exporting app data that does not need the grid export pipeline.
pnpm add write-excel-fileimport writeXlsxFile from 'write-excel-file';
await writeXlsxFile( [ [ { value: 'Name', fontWeight: 'bold' }, { value: 'Revenue', fontWeight: 'bold' }, ], [ { value: 'North', type: String }, { value: 12000, type: Number, format: '$#,##0' }, ], ], { fileName: 'summary.xlsx', sheet: 'Summary', },);The tradeoff is intentional simplicity. If export needs template workbooks, charts, complex formulas, images, or heavy workbook editing, use ExcelJS or a custom provider.
RevoGrid Import Pipeline
Section titled “RevoGrid Import Pipeline”For RevoGrid imports, keep the parser separate from the grid:
- Read the uploaded file.
- Parse workbook data with the selected library.
- Normalize headers into stable
ColumnRegularobjects. - Normalize each row into a plain object keyed by
column.prop. - Validate and coerce values before assigning them to the grid.
- Assign
grid.columnsbeforegrid.source.
type ImportedTable = { columns: { prop: string; name: string }[]; rows: Record<string, unknown>[];};
async function importWorkbook(file: File): Promise<ImportedTable> { return parseSheetJsFile(file);}
const imported = await importWorkbook(file);
grid.columns = imported.columns;grid.source = imported.rows;Avoid putting the raw workbook object into reactive application state. Workbooks can be large and contain circular or library-specific objects. Store the normalized rows, validation errors, and lightweight import metadata instead.
Performance Notes
Section titled “Performance Notes”Browser-side Excel parsing becomes visible to users once files are large enough. The exact threshold depends on column count, formulas, styles, browser, device, and parser options, but imports around 100k+ rows are where main-thread parsing commonly starts to feel expensive.
For larger files:
- Parse inside a Web Worker.
- Limit the first preview to a small row count.
- Normalize rows in chunks.
- Keep the original workbook out of framework state.
- Show validation errors separately from accepted rows.
- Let RevoGrid render the normalized dataset with virtualization.
For very large or regulated imports, parse on the backend and send RevoGrid paged or streamed JSON instead of asking the browser to own the whole workbook lifecycle.
Practical Choice
Section titled “Practical Choice”For most RevoGrid apps:
- Use
ExportExcelPluginwith the bundledwrite-excel-fileprovider for grid export. - Use SheetJS for flexible
.xlsxupload and header inference. - Use
read-excel-filefor small validated upload forms. - Use ExcelJS when the workbook itself is the product: formatted reports, templates, formulas, tables, and workbook editing.
That gives the fastest path for common XLSX-to-grid imports while keeping advanced export and workbook-editing cases open through RevoGrid’s custom provider contract.