ReoGrid ReoGrid Web

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;DRgrid.toJson() serializes the whole workbook; grid.loadJson(doc) restores it. For a single worksheet, use writeReoGridJson(ws) / readReoGridJson(ws, doc).


When to use it

Use caseFormat to reach for
Save / restore the full editor state (styles, formulas, cell types)ReoGrid JSON (lossless)
Auto-save to localStorage, IndexedDB, or your own backendReoGrid JSON
Undo snapshots, document versioningReoGrid JSON
Convert an .xlsx file to JSON in the browserReoGrid JSON via loadFromFiletoJson()
Pull plain rows of data out for an API / database / AIPlain 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

FunctionInputReturns
writeReoGridJson(ws, opts?)one Worksheet, or { name, worksheet }[]ReoGridJsonDocument
stringifyReoGridJson(ws, opts?)same, plus { pretty }string
parseReoGridJson(str)JSON stringvalidated ReoGridJsonDocument
readReoGridJson(ws, doc, opts?)worksheet + documentthe 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

ContentReoGrid JSONxlsx round-trip
Cell values, formulas
Styles, number formats, rich text
Merges, borders, column/row sizes
Freeze panes, hidden rows/cols
Conditional formatting, validationpartial
Outlines / grouping
Filter statepartial
Custom cell types (checkbox, dropdown, progress)❌ (xlsx has no concept)
Cell protection, alternate rowspartial
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

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.