@veltdev/superdoc-crdt-react and @veltdev/superdoc-crdt libraries enable real-time collaborative editing on SuperDoc Editors. The collaboration editing engine is built on top of Yjs and Velt SDK.
Prerequisites
- Node.js (v14 or higher)
- 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
Install the required packages:- React / Next.js
- Other Frameworks
Step 2: Setup Velt
Initialize Velt, authenticate a user, and set a stable document context before collaboration starts. Follow the Velt Setup Docs for the production token endpoint used byauthProvider.
- React / Next.js
- Other Frameworks
Wrap the app with an authenticated
VeltProvider, then set the document after the current user is available:Step 3: Initialize Collaborative Editor
- Initialize the collaboration manager and use the returned collaboration config to create the SuperDoc editor.
- Pass an
editorIdto uniquely identify each editor instance you have in your app. This is especially important when you have multiple editors in your app. - Users with the same Velt document context and
editorIdedit the same shared document.
- React Hook
- Other Frameworks
Use the
useCollaboration hook to manage the entire CRDT lifecycle. It creates a CollaborationManager, initializes the CRDT store, and returns the collaboration config expected by SuperDoc.Pass the same
collaboration object to both the SuperDoc document entry and modules.collaboration. It contains the Velt-backed Y.Doc and sync provider that SuperDoc uses for collaborative editing.Step 4: Status Monitoring (Optional)
- React / Next.js
- Other Frameworks
The hook returns reactive For event-style subscriptions, use the manager:
status, isSynced, and error state:Step 5: Version Management (Optional)
Save and restore named snapshots of the document state. Restored versions are applied to every connected user in real time.- React / Next.js
- Other Frameworks
Step 6: Force Reset Initial Content (Optional)
By default,initialContent is applied only when the shared document is brand new. Pass forceResetInitialContent: true to clear the existing shared SuperDoc state during initialization and reapply the initial-content flow.
- React / Next.js
- Other Frameworks
Step 7: Configure Remote Cursors
- React / Next.js
- Other Frameworks
SuperDoc’s paginated presentation layer renders remote cursors from the shared awareness state. Hide the embedded y-prosemirror cursor decorations to avoid duplicate cursor labels for the same user:
primitives.awareness or manager.getAwareness() when you need to build custom presence UI.
Step 8: CRDT Event Subscription (Optional)
Listen for real-time CRDT data events through the optionalgetCrdtElement() accessor on the Velt client.
- React / Next.js
- Other Frameworks
Step 9: Custom Encryption (Optional)
Encrypt CRDT data before it is stored in Velt by registering a custom encryption provider. For CRDT methods, input data is of typeUint8Array | number[].
- React / Next.js
- Other Frameworks
Step 10: Error Handling (Optional)
Pass anonError callback to handle initialization or runtime errors. The reactive error state is also available for rendering.
- React / Next.js
- Other Frameworks
Step 11: Access Yjs Internals (Advanced)
The hook and manager expose escape hatches for direct Yjs manipulation when needed.- React / Next.js
- Other Frameworks
supereditor fragment or clear its parts, meta, or media maps while users are editing. Use resetSuperDocState() only for a deliberate shared reset.
Step 12: Cleanup
- React / Next.js
- Other Frameworks
The hook destroys the manager automatically when the component unmounts or when the Set
editorId or Velt client changes. Destroy the SuperDoc instance in the same effect that creates it.enabled: false to tear down collaboration early while keeping the React component mounted.Notes
- Unique editorId: Use a unique
editorIdper editor instance. - Document context: Users must share both the same Velt document context and
editorIdto collaborate. - SuperDoc config: Pass
collaborationto both the collaborative document entry andmodules.collaboration. - Authenticated user: The hook waits for the Velt client to initialize and for a user to be identified before creating the collaboration manager.
- React remote cursors: Keep SuperDoc’s presentation cursor overlay enabled and hide the embedded y-prosemirror cursor decorations to avoid duplicate labels.
- Other Frameworks remote cursors: Disable SuperDoc’s presentation presence overlay and keep the y-prosemirror cursor decorations visible. Use exactly one cursor renderer per integration.
- Lifecycle: The hook reinitializes collaboration when the
editorIdor Velt client changes and destroys the previous manager. - Other Frameworks lifecycle: Unsubscribe listeners, destroy SuperDoc, and then destroy the manager.
- Yjs dependency: Keep a single copy of
yjsand compatible SuperDoc/wrapper versions in the application bundle. - Production authentication: Do not expose privileged server tokens in browser code; use Velt’s recommended server-backed authentication flow.
Testing and Debugging
To test collaboration:- Log in as two unique users in two separate browser profiles and open the same Velt document and SuperDoc
editorIdin both. - Edit text or formatting in one window and verify the changes and remote cursor appear in the other.
- Reload both windows and verify the shared document persists.
- Editor not loading: Confirm the Velt client is initialized, the user is authenticated, and
collaborationis available before creating SuperDoc. - Changes not syncing: Confirm both users have the same Velt document context and
editorId. - Duplicate cursor labels in React: Hide
.ProseMirror-yjs-cursorand.ProseMirror-yjs-selectionwhile leaving SuperDoc’s presentation cursor overlay enabled. - Duplicate cursor labels in Other Frameworks: Disable
layoutEngineOptions.presencein SuperDoc and leave the y-prosemirror cursor decorations visible. - Stale editor after changing documents: Destroy the existing SuperDoc instance and let the hook reinitialize with the new
editorId.
Complete Example
- React / Next.js
- Other Frameworks
A complete collaborative SuperDoc editor with Velt setup, user login, status display, remote-cursor styling, and version management.Add the remote-cursor styles to your global stylesheet:
Complete App.tsx
How It Works
- Velt initialization and authentication happen through
VeltProviderin React orinitVelt()andidentify()in other frameworks. Both paths establish the same stable document context. - The React hook or framework-agnostic factory creates one
CollaborationManagerfor the suppliededitorIdafter Velt is ready. - The manager creates an XML CRDT store backed by a Yjs document and Velt’s real-time sync provider.
getCollaborationConfig()exposes the manager-ownedY.Docand provider. SuperDoc receives the same instances in its document entry andmodules.collaborationconfiguration.- SuperDoc’s y-prosemirror binding writes text, formatting, and document structure into the shared Yjs document.
- Remote changes and cursors arrive through the provider and awareness state. Configure exactly one cursor renderer to avoid duplicate labels.
- Version management saves the complete Yjs state as a named snapshot. Restoring a version broadcasts the restored state to all connected users.
- React cleanup destroys the manager automatically while the editor effect destroys SuperDoc. Other frameworks unsubscribe callbacks, destroy SuperDoc, and then destroy the manager explicitly.
APIs
Other Frameworks: createCollaboration()
Creates and initializes aCollaborationManager from @veltdev/superdoc-crdt. Pass an initialized, authenticated Velt client, then call getCollaborationConfig() to obtain the { ydoc, provider } pair for SuperDoc.
- Signature:
createCollaboration(config: CollaborationConfig): Promise<CollaborationManager> - Cleanup: Call
manager.destroy()when you dispose the editor.
React: useCollaboration()
The primary React hook for collaborative SuperDoc editing. It creates aCollaborationManager, initializes the CRDT store, and returns the collaboration config expected by SuperDoc.
- Signature:
useCollaboration(config: UseCollaborationConfig): UseCollaborationReturn - Alias:
useSuperDocCollaboration - Params:
UseCollaborationConfigeditorId: Unique identifier for the collaborative editor.veltClient: Optional explicit Velt client. Falls back to theVeltProvidercontext.enabled: Set tofalseto delay initialization or tear down active collaboration. Default:true.initialContent: Optional initial-content marker applied to a brand-new shared document.forceResetInitialContent: Clear the current shared SuperDoc state during initialization. Default:false.debounceMs: Throttle interval in milliseconds for backend writes. Default:0.disableAwarenessUser: Disable automatic awareness user setup. Default:false.onError: Callback for non-fatal collaboration errors.
- Returns:
UseCollaborationReturncollaboration:{ ydoc, provider }for SuperDoc.nullwhile loading.collaborationConfig: Alias ofcollaboration.primitives: Lower-level Yjs and Velt collaboration handles.nullwhile loading.isLoading:trueuntil the manager is initialized.isSynced:trueafter the initial backend sync completes.synced: Alias ofisSynced.status: Connection status:'connecting','connected', or'disconnected'.error: Most recent error, ornull.manager: The underlyingCollaborationManager, ornullbefore initialization.versions: Reactive list of saved versions.saveVersion: Save a named snapshot and refreshversions.restoreVersion: Restore a saved version by ID.refreshVersions: Refresh and return the saved-version list.
SuperDocCollaborationConfig
The exact collaboration shape expected by SuperDoc’s collaborative document entries andmodules.collaboration option.
CollaborationPrimitives
Lower-level handles returned asprimitives for advanced integrations.
Version
Saved versions use the following shape:CollaborationManager Methods
The manager is available from theuseCollaboration return value after initialization.
manager.getCollaborationConfig()
Returns the{ ydoc, provider } object expected by SuperDoc, or null before initialization.
- Returns:
SuperDocCollaborationConfig | null
manager.getCollaborationPrimitives()
Returns the lower-level collaboration handles, ornull before initialization.
- Returns:
CollaborationPrimitives | null
manager.onStatusChange()
Subscribe to connection status changes.- Signature:
manager.onStatusChange(callback: (status: SyncStatus) => void): Unsubscribe
manager.onSynced()
Subscribe to initial sync state changes.- Signature:
manager.onSynced(callback: (synced: boolean) => void): Unsubscribe
manager.initialized
Whetherinitialize() has completed.
- Returns:
boolean
manager.synced
Whether initial sync with the backend has completed.- Returns:
boolean
manager.status
Current connection status.- Returns:
SyncStatus('connecting' | 'connected' | 'disconnected')
manager.saveVersion()
Save a named snapshot and return its version ID.- Signature:
manager.saveVersion(name: string): Promise<string>
manager.getVersions()
List all saved versions.- Returns:
Promise<Version[]>
manager.restoreVersion()
Restore a saved version. The restored state is sent to all connected users.- Signature:
manager.restoreVersion(versionId: string): Promise<boolean>
manager.setStateFromVersion()
Apply aVersion object’s state to the current document.
- Signature:
manager.setStateFromVersion(version: Version): Promise<void>
manager.resetSuperDocState()
Clear the shared SuperDoc XML content and metadata maps. This is the low-level reset used byforceResetInitialContent.
- Returns:
boolean
manager.getDoc()
Get the underlying Yjs document.- Returns:
Y.Doc | null
manager.getXmlFragment()
Get the Yjs XML fragment used by SuperDoc.- Returns:
Y.XmlFragment | null
manager.getProvider()
Get the Velt sync provider.- Returns:
SyncProvider | null
manager.getAwareness()
Get the Yjs awareness instance used for remote users and cursors.- Returns:
Awareness | null
manager.getStore()
Get the underlying Velt CRDT store.- Returns:
Store<string> | null
manager.destroy()
Destroy the store, provider listeners, and awareness state. The React hook calls this automatically during cleanup.- Returns:
void
Custom Encryption
Encrypt CRDT data before it is stored in Velt by registering a custom encryption provider. For CRDT methods, input data is of typeUint8Array | number[].

