ReoGrid ReoGrid Web

Reading and writing Excel files in JavaScript — import, export, and JSON

· unvell team
Reading and writing Excel files in JavaScript — import, export, and JSON

There are two common ways to handle Excel files in a web app. One is server-side: ship the file to a backend, parse it with a library, send data back. The other is client-side: read and write the file directly in the browser, so it never touches a server.

ReoGrid Web does the second — and unlike a headless parser, it also renders the file in an editable grid, with cell styles, merged cells, borders, and number formats preserved through the round-trip. This post covers the four operations you’ll actually need: import, export, xlsx→JSON, and JSON→grid.


Import: load an .xlsx file

xlsx import works in both the free Lite tier and Pro. There are four entry points depending on where the bytes come from:

import { createReogrid } from '@reogrid/lite';

const { worksheet } = createReogrid('#grid');

// From a file the user picked
await worksheet.loadFromFile(file);            // File object

// From a URL on your server
await worksheet.loadFromUrl('/data/report.xlsx');

// From raw bytes (e.g. a fetch response or drag-drop)
await worksheet.loadFromBuffer(arrayBuffer);   // ArrayBuffer | Uint8Array

Wiring up a file input is the most common case:

const input = document.querySelector<HTMLInputElement>('#file')!;
input.addEventListener('change', async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (file) await worksheet.loadFromFile(file);
});

loadFromFile resolves once cells, styles, merges, borders, number formats, and images have all been applied — so awaiting it means the grid is ready. Because everything runs in the browser, the file never leaves the user’s device (great for privacy — that’s exactly how our free online XLSX viewer works).


Export: save the grid as .xlsx

Exporting is a Pro feature. The simplest form triggers a browser download:

import { createReogrid } from '@reogrid/pro';

const { worksheet } = createReogrid('#grid');
// ...build or edit the grid...

worksheet.saveAsXlsx({
  filename: 'report.xlsx',
  sheetName: 'Q1 2026',
});

What gets written: cell values, formulas (with cached results so Excel shows numbers immediately), styles, number formats, merged cells, borders, row/column sizes, conditional formatting, and embedded images. A loadXlsxsaveAsXlsx round-trip preserves all of it.

Export without downloading

To get the xlsx bytes instead of a download — to upload them, attach to a form, or store them — build from a snapshot:

import { buildXlsxFromSnapshot } from '@reogrid/pro';

const snapshot = worksheet.getExportSnapshot();
const bytes: Uint8Array = buildXlsxFromSnapshot(snapshot, 'Sheet1');

await fetch('/api/upload', {
  method: 'POST',
  headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
  body: bytes,
});

xlsx → JSON

Often you don’t want the file — you want the data. After loading an xlsx (or building a grid), read cell values with worksheet.cell(row, col).value and assemble whatever shape you need:

await worksheet.loadFromFile(file);

const HEADER_ROW = 0;
const COLS = 3;            // however many columns your sheet uses
const rows: Record<string, string>[] = [];

// Read headers
const headers: string[] = [];
for (let c = 0; c < COLS; c++) {
  headers.push(worksheet.cell(HEADER_ROW, c).value ?? `col${c}`);
}

// Read data rows until an empty first cell
for (let r = HEADER_ROW + 1; ; r++) {
  const first = worksheet.cell(r, 0).value;
  if (first == null || first === '') break;
  const obj: Record<string, string> = {};
  for (let c = 0; c < COLS; c++) {
    obj[headers[c]] = worksheet.cell(r, c).value ?? '';
  }
  rows.push(obj);
}

console.log(JSON.stringify(rows, null, 2));

You now have a clean array of objects from any uploaded spreadsheet — no server round-trip.


JSON → grid

The reverse — turning an array of objects into a grid — is a one-pass write. (See the full bulk-load recipe for the performance details.)

const data = [
  { product: 'Widget', price: 9.99, qty: 40 },
  { product: 'Gadget', price: 24.5, qty: 12 },
];

const columns = ['product', 'price', 'qty'] as const;

columns.forEach((key, c) =>
  worksheet.cell(0, c).setValue(key).setStyle({ bold: true }),
);
data.forEach((row, r) =>
  columns.forEach((key, c) => worksheet.cell(r + 1, c).setValue(String(row[key]))),
);

From there you can saveAsXlsx() to turn JSON straight into a downloadable Excel file — a common “export my table to Excel” feature in two steps.


What about CSV?

CSV is just text, so it doesn’t need a heavy library: split the string into the grid on import, and read .value cells into a comma-joined string on export — the same cell-reading loop as the JSON section. If you need true Excel features (multiple sheets, styles, formulas, formats), use xlsx; if you only need flat rows of text, CSV via the cell API is enough.


Lite vs Pro

OperationLite (free)Pro
Import xlsx (loadFrom*)
Read cells → JSON
Write JSON → grid✅ (≤100×26)
Export xlsx (saveAsXlsx)
Built-in functions in formulas

So reading Excel in the browser is free; writing Excel is the Pro line.


Wrapping up

Doing Excel I/O in the browser keeps files on the user’s device, removes a server round-trip, and — with ReoGrid — gives you an editable, faithful view of the spreadsheet instead of a blind parse. Start with the XLSX I/O docs, grab the load and save recipes, or try the live demos.

Try ReoGrid Web in your project

Canvas-based Excel-compatible spreadsheet component for React and Vue. Lite is free — start with one npm install.

Related articles

Stay Updated

Be first to know — get updates as they ship

Get notified of new releases, features, and announcements.
No spam — just updates that matter.