ReoGrid JSON Format
ReoGrid JSON is the native serialization format for a ReoGrid workbook. Unlike xlsx — which is an interchange format and lossy for ReoGrid-specific features — ReoGrid JSON is lossless: it round-trips everything the runtime needs, including custom cell types, conditional-format rules, validation, outlines, named ranges, and protection.
Because ReoGrid can also read xlsx, the same API doubles as an xlsx → JSON converter: load a .xlsx file into a grid, then call toJson(). Everything runs in the browser — the file never touches a server.
TL;DR —
grid.toJson()serializes the whole workbook;grid.loadJson(doc)restores it. For a single worksheet, usewriteReoGridJson(ws)/readReoGridJson(ws, doc).
When to use it
| Use case | Format to reach for |
|---|---|
| Save / restore the full editor state (styles, formulas, cell types) | ReoGrid JSON (lossless) |
Auto-save to localStorage, IndexedDB, or your own backend | ReoGrid JSON |
| Undo snapshots, document versioning | ReoGrid JSON |
Convert an .xlsx file to JSON in the browser | ReoGrid JSON via loadFromFile → toJson() |
| Pull plain rows of data out for an API / database / AI | Plain data JSON — see Extract Excel data as JSON |
ReoGrid JSON keeps everything. If all you want is the cell values as an array of objects, see the data-extraction recipe instead — it produces a smaller, app-friendly shape.
Quick start (single worksheet)
The worksheet-level helpers are re-exported from both @reogrid/lite and @reogrid/pro — no deep imports.
import {
createReogrid,
writeReoGridJson,
readReoGridJson,
parseReoGridJson,
type ReoGridJsonDocument,
} from '@reogrid/lite';
const { worksheet } = createReogrid('#grid');
// Serialize → string
const doc: ReoGridJsonDocument = writeReoGridJson(worksheet);
localStorage.setItem('my-sheet', JSON.stringify(doc));
// Restore
const saved = localStorage.getItem('my-sheet');
if (saved) {
const parsed = parseReoGridJson(saved); // string → validated document
readReoGridJson(worksheet, parsed); // apply to the worksheet
}
parseReoGridJson validates the document (checks the format magic string and the major version) and throws on a mismatch, so you never apply a foreign or corrupt file by accident.
Whole workbook (all sheets)
When you have a multi-sheet workbook, the instance-level methods serialize and restore every sheet plus the active-sheet index in one call:
const grid = createReogrid('#grid');
// Save the entire workbook
const doc = grid.toJson();
await fetch('/api/save', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(doc),
});
// Load it back later
const doc2 = await (await fetch('/api/load')).json();
grid.loadJson(doc2); // replaces all sheets, activates doc.workbook.activeSheet
loadJson accepts unknown and validates before applying — pass it a parsed object straight from response.json().
Convert xlsx → JSON
Combine xlsx import with toJson() to convert a spreadsheet to JSON entirely client-side:
const grid = createReogrid('#grid');
document.querySelector<HTMLInputElement>('#file')!
.addEventListener('change', async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
await grid.loadFromFile(file); // parse + render the .xlsx
const json = grid.toJson(); // full-fidelity ReoGrid JSON
console.log(JSON.stringify(json, null, 2));
});
Lite vs Pro. xlsx import works in both tiers, but Lite truncates files larger than 100 rows × 26 columns. For converting arbitrary real-world spreadsheets without truncation, use Pro. See the online XLSX → JSON converter for a ready-made tool, or the xlsx-to-json recipe for the snippet.
API reference
| Function | Input | Returns |
|---|---|---|
writeReoGridJson(ws, opts?) | one Worksheet, or { name, worksheet }[] | ReoGridJsonDocument |
stringifyReoGridJson(ws, opts?) | same, plus { pretty } | string |
parseReoGridJson(str) | JSON string | validated ReoGridJsonDocument |
readReoGridJson(ws, doc, opts?) | worksheet + document | the worksheet (applies the first sheet) |
readReoGridJsonAll(doc, opts) | document + { createWorksheet } | { sheets, activeSheet } |
grid.toJson() | — | whole-workbook ReoGridJsonDocument |
grid.loadJson(doc) | document (unknown) | void (replaces all sheets) |
Write options
writeReoGridJson(worksheet, {
sheetName: 'Q3', // name when passing a single worksheet
activeSheet: 0, // index active on load (multi-sheet)
definedNames: [{ name: 'TaxRate', address: "Sheet1!$B$1" }],
meta: { appName: 'Budget App', author: 'jane', createdAt: '2026-06-27T00:00:00Z' },
});
stringifyReoGridJson(worksheet, { pretty: true }); // 2-space indented string
Read options
readReoGridJson(worksheet, doc, {
rebuildFormulas: false, // defer recalculation for bulk loads, then call ws.rebuildFormulas()
});
Multiple sheets
writeReoGridJson accepts an array; readReoGridJsonAll rebuilds them via a factory you supply (your app owns sheet tabs above this layer):
import { writeReoGridJson, readReoGridJsonAll } from '@reogrid/lite';
// Write several worksheets into one document
const doc = writeReoGridJson([
{ name: 'Jan', worksheet: janSheet },
{ name: 'Feb', worksheet: febSheet },
], { activeSheet: 1 });
// Read them back — createWorksheet produces a fresh sheet per entry
const { sheets, activeSheet } = readReoGridJsonAll(doc, {
createWorksheet: () => new Worksheet(),
});
For the common case of a workbook bound to a grid, prefer grid.toJson() / grid.loadJson() — they handle the tab bar and active sheet for you.
Document anatomy
The format is designed to stay compact on real files. Cells, styles, merges, and borders are stored as sparse arrays (never dense matrices), keys are short (r, c, v, f, s), styles and number formats live in shared dictionaries referenced by index, and row/column sizes are run-length encoded.
{
"format": "reogrid-json", // magic string — readers reject mismatches
"version": 1, // major version — readers reject newer
"meta": { "appName": "Budget App", "modifiedAt": "2026-06-27T09:00:00Z" },
"workbook": {
"activeSheet": 0,
"sheets": [
{
"name": "Sheet1",
"rowCount": 100,
"columnCount": 26,
"cells": [
{ "r": 0, "c": 0, "v": "Region", "s": 1 }, // v = value, s = style index
{ "r": 1, "c": 0, "v": "Tokyo" },
{ "r": 1, "c": 1, "v": "1200" },
{ "r": 2, "c": 1, "f": "=B2*1.1" } // f = formula source
],
"merges": [{ "r": 0, "c": 0, "rs": 1, "cs": 3 }]
}
]
},
"styles": [ {}, { "bold": true, "bg": "#f1f5f9" } ], // index 0 = default style
"numberFormats": ["General", "#,##0.00"],
"definedNames": [{ "name": "TaxRate", "address": "Sheet1!$B$1" }]
}
Files are not meant to be hand-edited — the writer always produces the most compact valid document, and the reader tolerates any valid document regardless of those optimizations.
What’s preserved
| Content | ReoGrid JSON | xlsx round-trip |
|---|---|---|
| Cell values, formulas | ✅ | ✅ |
| Styles, number formats, rich text | ✅ | ✅ |
| Merges, borders, column/row sizes | ✅ | ✅ |
| Freeze panes, hidden rows/cols | ✅ | ✅ |
| Conditional formatting, validation | ✅ | partial |
| Outlines / grouping | ✅ | ✅ |
| Filter state | ✅ | partial |
| Custom cell types (checkbox, dropdown, progress) | ✅ | ❌ (xlsx has no concept) |
| Cell protection, alternate rows | ✅ | partial |
Named ranges (definedNames) | ✅ | ✅ |
Use ReoGrid JSON when you want the editor to reopen exactly as the user left it. Use xlsx when the file has to be opened in Excel or another tool.
See also
- XLSX Import & Export — load and save
.xlsx - Convert XLSX to JSON in the browser — the how-to article
- Extract Excel data as JSON for your app — plain row objects
- Batch-process spreadsheet data with AI — xlsx → JSON → LLM
- Recipes: xlsx → JSON · xlsx → data rows