@veltdev/spreadjs-crdt-react and @veltdev/spreadjs-crdt libraries enable real-time collaborative workbook editing with MESCIUS SpreadJS. The collaboration engine serializes workbook state into a Velt CRDT Store backed by Yjs.
Prerequisites
- Node.js (v14 or higher)
- A Mescius SpreadJS license for production use, as required by Mescius
- A Velt account with an API key (sign up)
- React (v18 or higher) when using the React wrapper
- Optional: TypeScript for type safety
Setup
Step 1: Install Dependencies
- React / Next.js
- Other Frameworks
@mescius/spread-sheets@^19.1.3. Use the peer-compatible version, configure a production license before constructing a workbook, and do not commit production license keys to public source control.
Step 2: Create the Workbook
Create a host with stable dimensions, apply the license, and construct the workbook before creating collaboration. The drop-in React component performs these steps internally; React hook and Other Frameworks integrations own the workbook themselves.display: none, recreate the host while collaboration is active, or remove it before the manager has detached its event handlers and overlays.
Step 3: Setup Velt
React applications initialize Velt at the app root while the workbook component mounts. Other Frameworks integrations initialize Velt after constructing the workbook. In both cases, authenticate the user and set a stable document before creating collaboration. Follow the Velt Setup Docs for the production token endpoint used byauthProvider.
- React / Next.js
- Other Frameworks
Step 4: Initialize Collaborative Workbook
- React Component
- React Hook
- Other Frameworks
SpreadJSCrdtWorkbook creates one workbook per mount and connects it to the CRDT manager:licenseKey prop is optional. When provided, the wrapper applies it before creating the workbook. You can omit the prop if your application configures the license elsewhere, but Mescius licensing requirements still apply to production deployments.initializeWithoutWorkbook is enabled. Passing workbook to the factory or hook attaches it automatically; do not call attachWorkbook(workbook) again on the same initialization path.
Share collaboration through React context (optional)
useCollaborationContext() returns null outside the provider instead of throwing.
Step 5: Attach a Workbook Later (Optional)
- React / Next.js
- Other Frameworks
Initialize the manager before route data or a workbook exists:
attachWorkbook() after already passing that same workbook to the factory. One manager must not remain attached to multiple live workbooks.
Step 6: Status Monitoring (Optional)
- React / Next.js
- Other Frameworks
stats reports initialization, connection state, workbook attachment, Store availability, remote selection count, and the last flush reason.Step 7: Version Management (Optional)
- React / Next.js
- Other Frameworks
Step 8: Initial Content and Force Reset (Optional)
initialContent accepts raw SpreadJS workbook JSON or a WorkbookState object:
- React / Next.js
- Other Frameworks
initialContent and then attaches it to the workbook. Existing persisted state wins during normal initialization. forceResetInitialContent resets during manager creation; forceReset() is the explicit runtime reset. Calling forceReset() without an argument uses configured initialContent, or the current workbook JSON when no seed exists.
Step 9: Configure Serialization
The wrapper synchronizes complete workbook snapshots rather than individual cell operations:- Local event-driven writes call
workbook.toJSON(serializationOptions)after the configured debounce. - Remote Store updates call
workbook.fromJSON(json, deserializationOptions)while painting and SpreadJS events are suspended. - Direct helpers flush immediately, and deterministic snapshot signatures suppress echo loops.
toJSON() output as seed content and keep both option objects stable for a document family. Test formulas, bindings, named styles, formatting, comments, shapes, and workbook size with the options used in production.
This is a workbook-level snapshot strategy, not an operation-level cell CRDT. Overlapping edits to the same cell resolve through the latest accepted snapshot; the wrapper does not provide formula conflict resolution, operational locking, JSON compression, or cell-level merge policies.
Step 10: Cell, Sheet, and Formatting Helpers
- React / Next.js
- Other Frameworks
flushWorkbookToStore() after complex multi-step operations when immediate persistence is required.
Cell/value/range changes, active-sheet changes, sheet changes and renames, and selections are included in the event configuration. Highlights use SpreadJS backColor formatting and persist when the selected serialization options include that formatting.
Step 11: Configure Remote Selections (Optional)
- React / Next.js
- Other Frameworks
clearRemoteSelectionOverlays() on the manager when replacing the workbook host or implementing custom overlay cleanup.
The manager positions its pointer-transparent overlay inside workbook.getHost() by default and renders only selections for the active sheet. Remote selections on other sheets remain available through awareness.
The built-in overlay root uses data-velt-spreadjs-remote-selections. Selection rectangles use data-velt-spreadjs-selection, carets use data-velt-spreadjs-caret, and labels expose the collaborator name through data-velt-spreadjs-cursor-name. These attributes are stable hooks for tests and custom styling.
Step 12: CRDT Event Subscription (Optional)
- React / Next.js
- Other Frameworks
Step 13: Custom Encryption (Optional)
- React / Next.js
- Other Frameworks
Step 14: Error Handling (Optional)
- React / Next.js
- Other Frameworks
status, synced, and subscriptions for application control flow.
Step 15: Access Yjs Internals (Advanced)
- React / Next.js
- Other Frameworks
Step 16: Cleanup
- React / Next.js
- Other Frameworks
The hook destroys the manager automatically.
SpreadJSCrdtWorkbook also destroys the workbook it creates. When using the hook with an application-owned workbook, destroy collaboration before the workbook:Notes
- Snapshot model: SpreadJS workbook JSON is synchronized as a structured snapshot, not as independent CRDT cells.
- Store identity: The manager uses a
mapStore with content keyworkbookand source metadataspreadjs. - Debounced serialization: Local workbook events are batched before
toJSON()and Store writes; the default is 120 ms. - Serialization parity: Use compatible
serializationOptionsanddeserializationOptionsacross clients. - Workbook ownership: The component creates and destroys a workbook; the hook accepts an application-owned workbook.
- Awareness: Cell selections are transient presence state and do not appear in saved versions.
- Unique editorId: Collaborators must share the same Velt document and editor ID.
- Persistence: Reopening the same
editorIdreplays the persisted workbook snapshot; unrelated workbooks need different IDs. - Required events: Pass
GC.Spread.Sheets.Eventsso workbook, active-sheet, cell, range, value, sheet-name, and selection changes use the official event constants. - One attachment path: Passing
workbookduring creation attaches it automatically. UseattachWorkbook()only when the manager was initialized without that workbook or when replacing a detached workbook. - Lifecycle: Destroy the manager before destroying the application-owned workbook or removing its host.
- One Yjs instance: Deduplicate
yjsandy-protocolsso the wrapper and application share compatible Yjs constructors. - Behavioral boundary: Snapshot synchronization does not provide cell-operation merging, formula conflict resolution, operational locking, JSON compression, or application authorization.
- Production authentication: Use a server-backed Velt
authProvider; never expose privileged server tokens in browser code.
Testing and Debugging
To test collaboration:- Open the same Velt document and SpreadJS
editorIdas two different users. - Change cell values, formulas, formatting, sheet names, and selections.
- Verify remote workbook state, awareness overlays, version restore, and persistence after reload.
- Test large workbooks with the intended serialization options and debounce interval.
- Blank workbook host: Give the host an explicit height and verify the SpreadJS license.
- Workbook remains loading: Confirm Velt auth is ready and the workbook is attached, or use
initializeWithoutWorkbook. - Changes are missing: Pass
GC.Spread.Sheets.Eventsand compatible serialization options. - Conflicting cell edits overwrite each other: The adapter synchronizes complete workbook snapshots; add a product-level conflict policy for high-risk concurrent operations.
- Repeated full resets: Disable
forceResetInitialContentduring normal loads. - Overlay drift: Clear and rerender remote selections after sheet or viewport changes.
Complete Example
- React / Next.js
- Other Frameworks
Complete App.tsx
Complete styles.css
How It Works
- The application loads SpreadJS styles, applies its license, sizes the host, and creates the workbook before the normal collaboration path.
- React uses an authenticated
VeltProvider; other frameworks initialize one Velt client, authenticate the user, and set the document before creating the manager. - Passing the workbook and
GC.Spread.Sheets.Eventsattaches official workbook and active-sheet listeners during manager initialization. - Local events serialize
workbook.toJSON()into a versionedWorkbookState; remote state is applied withworkbook.fromJSON()while painting and events are suspended. - Awareness carries transient sheet ranges and active-cell metadata for pointer-transparent remote overlays.
- Versions, persistence, and reset operate on the complete serialized workbook snapshot.
APIs
React: SpreadJSCrdtWorkbook
React: useCollaboration()
The hook returns manager, workbook, lifecycle state, versions, remote selections, statistics, attachment helpers, reset/flush helpers, cell/sheet helpers, selection helpers, anddestroy().
Other Frameworks: createCollaboration()
Omit
workbook only for the documented attach-later lifecycle. Never pass it here and then attach the same instance again.
CollaborationManager Methods
Exported Types and Helpers
UseCollaborationConfig/UseSpreadJSCrdtConfig,UseCollaborationReturn/SpreadJSCrdtHookResultSpreadJSCrdtWorkbookProps,SpreadJSCrdtProviderProps,SpreadJSCollaborationManagerSpreadWorkbook,SpreadWorksheet,WorkbookJson,WorkbookState,WorkbookStoreAwarenessSelection,RemoteSelection,SpreadRange,CollaborationStatscloneJson(),stableStringify(),createWorkbookState(),createSelectionState()isWorkbookState(),hasWorkbookJson(),normalizeRanges()

