Tiptap provides first-class support for real-time collaborative editing through the Collaboration extension, which is powered by Yjs, a battle-tested CRDT (Conflict-free Replicated Data Type) framework.
The Collaboration extension requires a Yjs document to synchronize content between users.
import { Editor } from '@tiptap/core'import StarterKit from '@tiptap/starter-kit'import Collaboration from '@tiptap/extension-collaboration'import * as Y from 'yjs'// Create a Yjs documentconst ydoc = new Y.Doc()const editor = new Editor({ extensions: [ StarterKit.configure({ // Disable the default history extension // (collaboration comes with its own) history: false, }), Collaboration.configure({ document: ydoc, }), ],})
The Collaboration extension provides undo/redo functionality and real-time synchronization.
export interface CollaborationOptions { // An initialized Y.js document document?: Doc | null // Name of a Y.js fragment (for multiple fields in one document) field?: string // A raw Y.js fragment (alternative to document + field) fragment?: XmlFragment | null // The collaboration provider provider?: any | null // Callback when content is initially rendered onFirstRender?: () => void // Options for the Yjs sync plugin ySyncOptions?: YSyncOpts // Options for the Yjs undo plugin yUndoOptions?: YUndoOpts}
import { WebsocketProvider } from 'y-websocket'import * as Y from 'yjs'const ydoc = new Y.Doc()const provider = new WebsocketProvider('ws://localhost:1234', 'my-doc', ydoc)// Listen for connection statusprovider.on('status', (event: { status: string }) => { if (event.status === 'connected') { console.log('Connected to server') } else if (event.status === 'disconnected') { console.log('Disconnected from server') }})// Listen for sync eventsprovider.on('sync', (isSynced: boolean) => { if (isSynced) { console.log('Document synced') }})
import { IndexeddbPersistence } from 'y-indexeddb'import * as Y from 'yjs'const ydoc = new Y.Doc()// Persist to IndexedDBconst persistence = new IndexeddbPersistence('my-document', ydoc)persistence.on('synced', () => { console.log('Document loaded from IndexedDB')})
// User A types "Hello"// User B types "World" at the same position// Result: "HelloWorld" or "WorldHello" (deterministic)// Yjs ensures:// 1. All clients converge to the same state// 2. No data loss// 3. Causal consistency// 4. Intention preservation
Temporarily disable collaboration to prevent syncing.
// Check if disabledif (editor.storage.collaboration.isDisabled) { console.log('Collaboration is disabled')}// The extension can disable itself if content errors occureditor.on('contentError', ({ disableCollaboration }) => { // This will disable collaboration and prevent syncing disableCollaboration()})