How to compare workbook versions and highlight changes like Google Sheets Versi

Posted by: diep.nguyen on 29 September 2026, 11:17 pm EST

  • Posted 29 September 2026, 11:17 pm EST

    Hi SpreadJS team,

    We are using SpreadJS to build Excel-like tables, and we have a version history feature where each saved version of a workbook can be opened and previewed.

    We would like to add a feature similar to Google Sheets version history, where changes in the selected version are highlighted compared with the previous version. For example, if a cell value or formula was changed, we would like to identify and highlight that cell in the history preview.

    Does SpreadJS provide any API or built-in mechanism to compare two saved workbook versions and determine what changed between them?

    In particular, we are interested in detecting changes such as:

    • Cell value or formula changes
    • Inserted or deleted rows/columns
    • Added, deleted, or renamed sheets
    • Formatting changes, if possible

    Our workbook versions are stored separately and can be loaded back into SpreadJS, so we can access both the current version and the previous version as workbook data.

    If there is no built-in version comparison API, what would be the recommended approach for implementing this with SpreadJS? For example, is there a reliable way to compare two workbook JSON/SJS snapshots, or any change-tracking API that can be persisted and used for version history?

    The behavior we are aiming for is similar to the change highlighting shown in Google Sheets Version History.

    Thanks!

  • Posted 30 September 2026, 5:11 am EST

    Hi,

    To implement a version history feature with change detection and visual highlighting, there are two possible approaches depending on whether you are using the SpreadJS Collaboration Add-on or standard standalone SpreadJS.

    Option 1: Using the SpreadJS Collaboration Add-on (v19+)

    In SpreadJS v19, Mescius introduced the SpreadJS Collaboration Add-on (@mescius/spread-sheets-collaboration-addon) along with the Collaboration Server.

    The collaboration system provides built-in change tracking. It monitors workbook changes and records them as granular Operations (Ops) grouped into ChangeSets.

    The collaboration architecture also supports version transitions through snapshots and sequential ChangeSets, which can be used as the foundation for a version history feature.

    However, please note that although the Collaboration Add-on tracks the changes and maintains the required operational history, it does not currently provide an out-of-the-box visual diff UI or automatic Google Sheets–style highlighting.

    You can refer to the following documentation and demo for more information:

    SpreadJS Collaboration Server Documentation: https://developer.mescius.com/spreadjs/docs/spreadjs-collaboration-server

    SpreadJS Collaboration Demo: https://developer.mescius.com/spreadjs/demos/collaboration

    Option 2: Using Standalone SpreadJS without the Collaboration Add-on

    If you do not want to use the Collaboration Add-on and are instead saving standalone workbook versions as JSON or .sjs files, SpreadJS does not provide a built-in API to directly compare two static workbook snapshots and generate an operational delta.

    Performing a full JSON comparison after the fact is also not recommended for large workbooks. In addition to the performance considerations, it can be difficult to distinguish between direct cell changes and structural changes such as row or column insertions that shift existing cells.

    In this scenario, we recommend using an event-driven change-tracking approach.

    With this approach, you can listen to the native SpreadJS events while the user is working with the workbook, record the relevant changes in a lightweight delta buffer, and save that information along with each workbook version.

    When an older version is opened in Version History mode, the saved workbook snapshot can be loaded in read-only mode, and the previously recorded changes can then be used to apply the appropriate visual highlights.

    For example, the following changes can be tracked:

    Cell value and formula changes: Use GC.Spread.Sheets.Events.ValueChanged and GC.Spread.Sheets.Events.RangeChanged. The changed cells can then be highlighted with a background tint and a corner indicator.

    Inserted rows and columns: Use GC.Spread.Sheets.Events.RowChanged and GC.Spread.Sheets.Events.ColumnChanged, including the addRows and addColumns property changes. The corresponding row or column can be highlighted and its header can be marked to indicate the insertion.

    Deleted rows and columns: Use GC.Spread.Sheets.Events.RowChanging and GC.Spread.Sheets.Events.ColumnChanging with the deleteRows and deleteColumns property changes. A visual marker can be placed along the affected boundary to indicate where content was removed, and the change can also be recorded in a history sidebar.

    Added, deleted, or renamed sheets: Use GC.Spread.Sheets.Events.SheetChanged, GC.Spread.Sheets.Events.SheetChanging, and GC.Spread.Sheets.Events.SheetNameChanged. The affected sheet tabs can be visually marked and the changes can be displayed in the version history panel.

    Working Sample

    We have also prepared a runnable SpreadJS v19 sample for your reference. It demonstrates:

    Real-time tracking of workbook changes using SpreadJS events, including cell edits, row/column insertion and deletion, and sheet changes.

    Saving named version milestones.

    A Google Sheets–style version history sidebar.

    Visual highlighting of changed cells and structural changes.

    Sample: Sample.zip

    Regards,

    Priyam

  • Posted 5 October 2026, 12:38 am EST

    Hi Priyam,

    Thanks for the detailed explanation and sample. We did some further investigation on the Collaboration Add-on and have a few follow-up questions before deciding which approach fits our version history implementation best.

    1. Is the SpreadJS Collaboration Add-on licensed separately from the standard SpreadJS license? We tested it with our current license key and the collaboration feature appears to be disabled. If it requires an additional license, could you clarify the licensing/pricing model?
    2. For our use case, we do not need real-time co-editing. Can the Collaboration Add-on be used client-side only to record and replay ChangeSets, without using the Collaboration Server?
    3. Our versions are currently stored as .sjs/JSON snapshots and later loaded with fromJSON(). Are ChangeSets expected to replay reliably on a workbook reconstructed from fromJSON(), or do they depend on internal workbook/sheet identifiers from the original workbook instance?
    4. Is the structure/schema of the individual operations inside a ChangeSet documented anywhere? For example, can we reliably determine the affected sheet, row, column, value, style, inserted/deleted range, etc. from an operation?
    5. When ChangeSets are replayed, do normal SpreadJS events such as ValueChanged, RangeChanged, RowChanged, ColumnChanged, SheetChanged, etc. fire again? This would be useful for applying visual highlights while replaying changes.
    6. For the standalone event-driven approach, could you also clarify whether RangeChanged and the other suggested events reliably cover operations such as paste, drag-fill, clear/delete, sort, cut/paste, undo/redo, and programmatic changes? We want to make sure the change log cannot silently miss common spreadsheet edits.

      Our main goal is still a Google Sheets–style Version History view: open a saved version, identify what changed compared with the previous version, and highlight those changes accurately, including row/column insertions and deletions.

      Thanks again for your help.
  • Posted 5 October 2026, 8:22 am EST

    Hi,

    Thank you for following up and providing these additional details.

    Initially, your requirements focused on tracking core workbook changes, including:

    Cell value or formula changes

    Inserted or deleted rows and columns

    Added, deleted, or renamed sheets

    Formatting changes, if possible

    For this initial scope, we provided a sample demonstrating an event-driven approach. However, as your requirements have expanded to include more comprehensive operations, such as paste, drag-fill, cut/paste, sorting, clearing, undo/redo, and programmatic edits, we want to ensure that the proposed solution is reliable and does not miss changes in less common scenarios.

    Therefore, we have escalated this case to our core development team to confirm the following ( The internal track id is “SJS-36022”):

    Collaboration Add-on suitability: Whether the Collaboration Add-on can be adapted to support your client-side version history and change-highlighting requirements without significant limitations.

    Event-driven approach suitability: Whether an event-driven solution can reliably handle the expanded list of operations without missing changes.

    Built-in functionality or official workaround: Whether a built-in version comparison feature is available or could be considered, or whether the development team can recommend an officially supported approach for your use case.

    In the meantime, please find below our responses to your questions regarding licensing and the current behavior of SpreadJS.

    Collaboration Add-on Licensing

    Is the Collaboration Add-on licensed separately?

    Yes. The SpreadJS Collaboration Add-on is an optional feature that requires the appropriate entitlement in your SpreadJS license key.

    If your current license covers only the core SpreadJS functionality, the collaboration features will not be available at runtime. If you would like to evaluate the Collaboration Add-on, please contact sales team to request an evaluation key with the required entitlement enabled.

    For pricing information, please refer to the SpreadJS pricing page: https://developer.mescius.com/spreadjs/pricing.

    Client-Side-Only Usage of the Collaboration Add-on

    We are currently awaiting confirmation from our development team regarding whether the Collaboration Add-on can be adapted for your client-side-only version history workflow.

    The @mescius/spread-sheets-collaboration-addon package is designed to support collaborative scenarios involving backend connectivity. We need to confirm whether its functionality can be used or adapted for your specific requirements without relying on the standard collaboration backend.

    We will share the development team’s findings once we receive confirmation.

    Replaying ChangeSets on fromJSON() or .sjs Workbooks

    Currently, this is not supported out of the box.

    ChangeSets rely on internal session and sheet identifiers established through toSnapshot() and fromSnapshot(). Restoring a workbook through the standard fromJSON() API or loading an .sjs file restores the workbook model without the internal collaboration mappings required for ChangeSet application.

    Consequently, ChangeSets cannot be directly applied across these standard workbook restoration workflows.

    Op Structure and Schema Documentation

    Although the top-level OpType enum exposes operation types such as setRange, addRows, and deleteRows, the internal payload structures of individual operations are part of the Operational Transformation (OT) engine’s implementation.

    These payload structures are not currently documented or exposed as a public API for extracting details such as sheet identifiers, row and column coordinates, and old and new values for visual change comparison.

    Event Firing During applyChangeSet()

    Standard interactive UI events, such as ValueChanged and RangeChanged, do not fire when applyChangeSet() is called. These events are intentionally suppressed during ChangeSet application.

    Therefore, these events cannot be relied upon to detect changes applied through this API.

    Coverage of the Expanded Operations in the Event-Driven Approach

    In standard SpreadJS, different operations may trigger different events, so relying exclusively on ValueChanged may not capture every modification.

    Paste, drag-fill, and clearing a range: These operations may not trigger ValueChanged in the same way as editing an individual cell. You should review the available events and their behavior for each operation in the SpreadJS Events API documentation.

    Programmatic changes: Direct API calls such as sheet.setValue() do not necessarily trigger the same UI events as interactive edits. If you need command-based tracking, you may need to execute supported operations through spread.commandManager().execute() using the appropriate command, such as editCell, where applicable.

    Given these differences, we recommend waiting for our development team’s confirmation before finalizing the architecture for your version history and change-highlighting workflow.

    We will update you as soon as we receive further information regarding the recommended approach.

    Regards,

    Priyam

  • Posted 12 October 2026, 8:32 am EST

    Hi,

    Thank you for your patience while we consulted our development team regarding your use case (Internal Track ID: SJS-36022).

    We have received direct feedback and architectural guidance from the development team regarding both the Collaboration Add-on and the standalone snapshot/event-driven approaches. Please find the detailed findings and recommendations below:

    Built-in Workbook Comparison API

    Official Status: SpreadJS currently does not provide a built-in public API (such as Workbook.compare(versionA, versionB)) that takes two independently saved .sjs or JSON workbooks and outputs an operational delta.

    Generating a Google Sheets–style visual diff with automatic change highlighting requires an application-level implementation.

    Follow-Up Questions on the Collaboration Add-on

    Client-Side-Only Usage (Without Collaboration Server):

    Yes, the Collaboration Add-on can be used entirely on the client side to capture and replay ChangeSets locally without needing the Collaboration Server. The official documentation includes an example demonstrating local persistence using localStorage: https://developer.mescius.com/spreadjs/docs/spreadjs-collaboration-server/spreadjs-sheets-collaboration/spreadjs-sheets-collaboration-add-on

    Compatibility with fromJSON() and .sjs Snapshots:

    While fromSnapshot() can load standard workbook JSON, ChangeSets strictly depend on internal document and sheet identifiers established during the collaboration session.

    Therefore, previously recorded ChangeSets cannot be reliably applied across workbooks restored via standard fromJSON() / .sjs unless they originate from the matching Collaboration Snapshot (toSnapshot() / fromSnapshot()).

    Additionally, existing historical revisions saved only as .sjs/JSON snapshots cannot retroactively be reconstructed into original ChangeSets.

    Inspecting Operations inside a ChangeSet:

    Through onChangeSet(), you can persist ChangeSets for replay, and the public interface exposes the operation list and high-level OpType.

    However, there is no public, stable schema designed to extract granular cell coordinates (sheet, row, column), old values, new values, or style diffs across all operation types. ChangeSets are strictly designed for the Operational Transformation (OT) replay engine rather than human-readable diff reporting.

    Events During applyChangeSet() Replay:

    Standard UI events (such as CellChanged and ValueChanged) are not guaranteed to fire across workbook model replays during applyChangeSet() and cannot be relied upon to paint visual highlights during replay.

    Event-Driven & Programmatic Coverage

    Programmatic API Calls:

    Standard calls such as sheet.setValue() and sheet.setFormula() can raise the CellChanged event. Routing every setter through spread.commandManager().execute() is therefore not a strict requirement for basic event firing.

    Full Coverage Considerations:

    While basic edits raise events, listening exclusively to commands or event listeners does not automatically guarantee 100% complete tracking across all complex operations.

    Any event-driven tracking approach must be carefully tailored and validated against the specific workbook features, operations, and dataset sizes your application supports.

    Recommended Architectural Approaches

    Based on the development team’s recommendations, here are the two viable paths depending on your workflow:

    Path A: For Existing / Independent Workbook Snapshots (.sjs / JSON) (Recommended for your current setup)

    If your application already manages versions as independent snapshots loaded via fromJSON() or .sjs:

    Application-Level State Comparator:

    Load the previous version and current version into memory.

    Compare structural elements first:

    Sheets: Added, removed, or renamed sheets (using stable sheet keys/names).

    Rows / Columns: Compare row and column counts or structural definitions to detect insertions and deletions.

    Compare content within active/used ranges:

    Cell values and formulas via sheet.getValue() / sheet.getFormula().

    Cell formatting/styles via sheet.getStyle().

    Dedicated Highlighting Layer:

    Once your comparator produces a diff list, render visual highlights on the active preview sheet:

    Use cell styles/background colors or border indicators for modified cells.

    Use custom indicators (such as header markers or subtle row/column highlights) for inserted/deleted ranges.

    Path B: For Future Version History Using the Collaboration Add-on

    If you plan to redesign the versioning pipeline from scratch:

    Store an initial Collaboration Snapshot (toSnapshot()), capture and store sequential ChangeSets via onChangeSet(), and periodically save new snapshots for fast milestone loading.

    Store your own metadata (author, timestamp, version tag) alongside each ChangeSet milestone.

    For change descriptions and visual highlighting, development recommends either:

    Comparing restored workbook states (as described in Path A) between milestone snapshots, or

    Recording structured change metadata in your application layer as actions occur, rather than trying to parse raw OT operations.

    Regards,

    Priyam

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels