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 packages for your application:- React / Next.js
- Other Frameworks
@veltdev/tinymce-crdt package provides the imperative manager and content helpers.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
Step 3: Load TinyMCE
You can load TinyMCE from your own bundle or from Tiny Cloud.- Self-hosted
- Tiny Cloud
Import TinyMCE, the theme, model, icons, plugins, and skin styles before rendering the editor:Set
licenseKey="gpl" on the editor when using TinyMCE under the GPL license.The default TinyMCE iframe mode uses its own content stylesheet. For self-hosted inline mode, also bundle the inline content styles and tell TinyMCE not to load skin files by URL:Step 4: Initialize Collaborative Editor
- Pass an
editorIdto uniquely identify the shared editor. - Use
initialContentonly as the seed for a brand-new shared document. - Do not pass
value,initialValue, oronEditorChange; the CRDT manager owns TinyMCE content.
- React Component
- React Hook
- Other Frameworks
TinyMceCrdtEditor is the simplest integration. It captures TinyMCE’s editor instance, waits for Velt and the current user, initializes collaboration, and cleans up automatically.@tinymce/tinymce-react props except value, initialValue, onEditorChange, and onInit, which are owned by the collaboration layer.Apply Formatting Programmatically
TinyMCE formatting synchronizes as part of the shared HTML. Use TinyMCE commands for toolbar actions or custom controls:lists and link plugins for their corresponding commands. forecolor maps to the text-color toolbar control, while hilitecolor maps to backcolor.
Step 5: Status Monitoring (Optional)
- React / Next.js
- Other Frameworks
The hook returns reactive With the hook:
status, isSynced, and error state. The component exposes equivalent callbacks, and the manager supports event subscriptions.onStatusChange(), onSynced(), and onRemoteCursorsChange() immediately invoke the callback with the current value when subscribed, then invoke it again for subsequent changes. Store and call every returned unsubscribe function.
Local editing remains available while the provider reconnects. Use status for UI feedback rather than as a typing lock.
Step 6: Version Management (Optional)
Save, list, and restore named CRDT snapshots with the hook or manager:- React / Next.js
- Other Frameworks
Step 7: Force Reset Initial Content (Optional)
initialContent is HTML and is applied once when the shared document is empty:
- React / Next.js
- Other Frameworks
forceResetInitialContent only for an explicit reset workflow:Step 8: Configure Remote Cursors (Optional)
The adapter publishes the local selection through Yjs awareness and renders remote caret and selection overlays automatically.- React / Next.js
- Other Frameworks
cursorsContainer, or set it to null to keep awareness active without injected cursor DOM:Step 9: CRDT Event Subscription (Optional)
Listen for real-time CRDT data events usinggetCrdtElement().on() from the Velt client.
- React / Next.js
- Other Frameworks
Step 10: 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 11: Error Handling (Optional)
PassonError to receive non-fatal initialization, sync, recovery, and content errors:
- React / Next.js
- Other Frameworks
Step 12: Access Yjs Internals (Advanced)
Use the manager only when you need lower-level integration points:Step 13: Cleanup
- React / Next.js
- Other Frameworks
The React component and hook destroy the collaboration manager automatically. The hook also returns
destroy() for early teardown.Notes
- Uncontrolled editor: The CRDT manager is the only owner of TinyMCE content; do not pass controlled content props.
- Unique editorId: Collaborators must share the same Velt document context and
editorId. - HTML data model: The adapter stores normalized HTML in a Yjs XML fragment and preserves the local selection while applying remote HTML.
- Debounced writes: Local editor changes are serialized after
debounceMs(125 ms by default). - Remote cursors: Cursor overlays work with iframe and inline TinyMCE modes; set
cursorsContainer={null}for custom rendering. - Initial content: Seed content is applied once unless
forceResetInitialContentis enabled. - Editor modes: The package supports both inline and iframe-mode TinyMCE editors.
- Other Frameworks lifecycle: Create TinyMCE before collaboration; unsubscribe listeners and destroy the manager before removing TinyMCE.
- Production authentication: Use Velt’s recommended server-backed authentication flow; never expose privileged server tokens in browser code.
Testing and Debugging
To test collaboration:- Log in as two unique users in separate browser profiles.
- Open the same Velt document and TinyMCE
editorIdin both. - Type and format content in one window and verify it appears in the other.
- Verify remote caret labels, selections, version restore, and persistence after reload.
- Editor not syncing: Confirm the user is identified, the Velt document is set, and both clients use the same
editorId. - Editor remains blank: Confirm all required self-hosted TinyMCE imports are loaded, or provide a Tiny Cloud API key.
- Local content is overwritten: Remove TinyMCE
value,initialValue, andonEditorChangeprops. - Cursors not appearing: Confirm both users are active and
cursorsContainerwas not set tonull. - Existing content resets: Do not enable
forceResetInitialContentduring normal loads.
Complete Example
- React / Next.js
- Other Frameworks
Complete App.tsx
How It Works
- Initialize and authenticate Velt through
VeltProviderin React orinitVelt()andidentify()in other frameworks, then set a stable document context. - Create TinyMCE before collaboration. The React component captures its editor automatically; the hook and framework-agnostic factory receive the existing instance.
- The manager opens a Velt CRDT store keyed by
editorIdand stores normalized HTML in a Yjs XML fragment. - Local TinyMCE changes are debounced and written to the shared document. Remote changes update TinyMCE while preserving the local bookmark or DOM selection.
- Yjs awareness carries user identity and selection data for remote cursor overlays in iframe and inline modes.
- Velt persists CRDT updates and named versions. Restoring a version refreshes TinyMCE and broadcasts the restored state.
- React wrappers destroy collaboration automatically. Other frameworks unsubscribe listeners, destroy the manager, and then remove the TinyMCE editor explicitly.
APIs
React: TinyMceCrdtEditor
*Provide either
editorId or documentId. Other supported TinyMCE React props are passed through, excluding the CRDT-owned content and initialization props.
React: useCollaboration()
The hook accepts the baseCollaborationConfig without editor and with an optional veltClient.
Other Frameworks: createCollaboration()
CollaborationManager Methods
Exported Types and Helpers
CollaborationConfigUseCollaborationConfig/UseTinyMceCrdtConfigUseCollaborationReturn/TinyMceCrdtHookResultTinyMceCrdtEditorPropsTinyMCEEditorLikeTinyMCECursorData,TinyMCECursorRect,TinyMCECursorSelection,TinyMCERemoteCursorSyncStatus,Unsubscribe,VersionnormalizeHtml(),readHtmlFromXmlFragment(),writeHtmlToXmlFragment()hasSharedHtml(),applyInitialContent()

