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 loadXlsx → saveAsXlsx 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
| Operation | Lite (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.