ReoGrid ReoGrid Web

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).value returns 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

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.