Skip to content

Excel Import & Export (with Merged Cells)

Read an .xlsx workbook into GridSheet and write it back out with @gridsheet/xlsx. Values, formulas (including cross-sheet references), cell styles, column widths / row heights and merged cells come through both ways. The demo loads a three-sheet sample whose titles are merged — or open (or drop) any .xlsx file of your own, edit it, and download the result.

Open any .xlsx file (or drop one here) — the sample loads by default and its titles are merged cells. Edit values or select a range and right-click → Merge cells, then download and open the result in Excel or another spreadsheet app.

📄 View Source Code
Terminal window
npm install @gridsheet/xlsx

@gridsheet/xlsx is headless (no DOM, no framework) — it converts bytes ⇄ GridSheet data, so it works the same in the browser and in Node.

fromXlsx takes the file’s bytes and returns one { matrices, cells } per sheet — exactly the shape buildInitialCells accepts:

import { fromXlsx } from '@gridsheet/xlsx';
const workbook = fromXlsx(new Uint8Array(await file.arrayBuffer()));
// { Sales: { matrices, cells }, 'Meta Data': { ... }, Summary: { ... } }
  • matrices holds the values; formulas arrive as their "=..." text.
  • cells holds per-cell styles, column widths / row heights, and merged ranges — a merge is stored on its top-left cell as merge: { rows, cols } (an Excel A1:D1 becomes A1: { merge: { rows: 1, cols: 4 } }).

Render every sheet into one shared book so cross-sheet formulas such as =SUM(Sales!D3:D5) resolve:

const book = useSpellbook({});
{Object.entries(workbook).map(([name, data]) => (
<GridSheet
key={name}
book={book}
sheetName={name}
sheetRef={refs.current[name]}
initialCells={buildInitialCells(data)}
/>
))}

initialCells is read only on mount, so remount the sheets (e.g. change a key) when a new file is opened.

toXlsx takes a map of sheet name → live sheet and returns the workbook as bytes. Passing the live sheets (from each sheetRef) includes the user’s edits and any cells they merged or unmerged:

import { toXlsx } from '@gridsheet/xlsx';
const sheets = Object.fromEntries(
Object.entries(refs.current).map(([name, ref]) => [name, ref.current!.sheet]),
);
const blob = new Blob([toXlsx(sheets)], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
// …then download it (object URL + <a download>) or upload it.

toXlsx also accepts plain value matrices ([['Name', 'Qty'], ['Apple', 3]]) or cell matrices, for generating a file without rendering a grid.

Users merge and unmerge from the right-click menu (Merge cells / Unmerge cells); in code, put merge: { rows, cols } on the anchor cell of initialCells. The covered cells stay empty — only the anchor holds a value, as in Excel.

Number formats (e.g. currency or date display formats), borders, frozen panes and charts are not read or written. Formula results aren’t cached in the file; spreadsheet apps recalculate on open.