Convert XLSX to Data Rows
The ReoGrid JSON document is lossless but verbose. When you just want the data — an array of row objects keyed by the header row — read the displayed cell values out of the grid after loading.
This is the shape you want for posting to an API, inserting into a database, or feeding an LLM.
The helper
import type { ReogridInstance } from '@reogrid/pro';
/** Read a worksheet as an array of row objects, using row 0 as the header. */
function sheetToRows(grid: ReogridInstance): Record<string, string>[] {
const ws = grid.worksheet;
// 1. Find the used extent from the sparse cell snapshot.
const snapshot = ws.getExportSnapshot();
let lastRow = 0;
let lastCol = 0;
for (const cell of snapshot.cells) {
if (cell.row > lastRow) lastRow = cell.row;
if (cell.column > lastCol) lastCol = cell.column;
}
// 2. Header row → column keys (getDisplayText returns the *rendered* value).
const headers: string[] = [];
for (let c = 0; c <= lastCol; c++) {
headers[c] = (ws.getDisplayText(0, c) || `col${c}`).trim();
}
// 3. Each data row → an object keyed by header.
const rows: Record<string, string>[] = [];
for (let r = 1; r <= lastRow; r++) {
const row: Record<string, string> = {};
for (let c = 0; c <= lastCol; c++) {
row[headers[c]] = ws.getDisplayText(r, c) ?? '';
}
rows.push(row);
}
return rows;
}
Use it
import { createReogrid } from '@reogrid/pro';
const grid = createReogrid('#grid', { licenseKey: 'YOUR-LICENSE-KEY' });
await grid.loadFromFile(file);
const rows = sheetToRows(grid);
console.log(rows);
// [
// { Product: 'Widget', Price: '9.99', Qty: '40' },
// { Product: 'Gadget', Price: '24.50', Qty: '12' },
// ]
await fetch('/api/import', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(rows),
});
Why getDisplayText, not cell.value?
ws.getDisplayText(r, c)returns the rendered value — formulas are evaluated and number formats applied ("1,200","$9.99"). This is what a human sees, and usually what an app wants.grid.worksheet.cell(r, c).valuereturns the raw input — for a formula cell that’s the source string ("=B2*1.1"), not the result.
Typed numbers instead of strings
getDisplayText returns strings. Coerce per column when you need real numbers:
const typed = rows.map((r) => ({
product: r.Product,
price: Number(r.Price.replace(/[^0-9.-]/g, '')), // strip $ , etc.
qty: Number(r.Qty),
}));
Notes
- Assumes the header is on row 0. If your sheet has a title banner, start the loop at the real header row.
- Empty trailing rows/columns are excluded automatically because the extent comes from the populated-cell snapshot.
- For the full, lossless document (styles, formulas, merges) instead of plain rows, use Convert XLSX to JSON.
See also
- Extract Excel data as JSON for your app (article)
- Batch-process spreadsheet data with AI (article)
- Bulk Load from JSON — the reverse direction