Document Sync
Document Sync
Realtime SDK uses Yjs for conflict-free collaborative editing. Multiple users can edit the same document simultaneously without conflicts.
How It Works
Yjs uses CRDTs (Conflict-free Replicated Data Types) to automatically merge changes from multiple users. There's no need for operational transforms or manual conflict resolution.
Basic Setup
import { useDocument } from '@realtime-sdk/react';
import * as Y from 'yjs';
function CollaborativeEditor({ room }) {
const { doc, synced } = useDocument(room, 'main');
if (!synced) {
return <div>Loading document...</div>;
}
return <Editor yDoc={doc} />;
}
Yjs Data Types
Yjs provides several shared data types:
Y.Text
For rich text editing:
const yText = doc.getText('content');
// Insert text
yText.insert(0, 'Hello, ');
yText.insert(7, 'world!');
// Get content
console.log(yText.toString()); // "Hello, world!"
Y.Array
For ordered lists:
const yArray = doc.getArray('items');
// Add items
yArray.push(['Item 1', 'Item 2']);
// Get items
console.log(yArray.toArray()); // ['Item 1', 'Item 2']
Y.Map
For key-value data:
const yMap = doc.getMap('settings');
// Set values
yMap.set('theme', 'dark');
yMap.set('fontSize', 14);
// Get values
console.log(yMap.get('theme')); // 'dark'
Editor Integrations
TipTap
import { useEditor } from '@tiptap/react';
import Collaboration from '@tiptap/extension-collaboration';
import CollaborationCursor from '@tiptap/extension-collaboration-cursor';
function TipTapEditor({ room }) {
const { doc, provider } = useDocument(room, 'main');
const { self } = usePresence(room);
const editor = useEditor({
extensions: [
StarterKit.configure({ history: false }),
Collaboration.configure({ document: doc }),
CollaborationCursor.configure({
provider,
user: { name: self?.data.name, color: self?.color },
}),
],
});
return <EditorContent editor={editor} />;
}
CodeMirror
import { yCollab } from 'y-codemirror.next';
function CodeMirrorEditor({ room }) {
const { doc, awareness } = useDocument(room, 'main');
const yText = doc.getText('code');
const extensions = [
yCollab(yText, awareness),
// ... other extensions
];
return <CodeMirror extensions={extensions} />;
}
Persistence
Documents are automatically persisted to the server:
- Changes are saved with a 2-second debounce
- On page load, the server sends the saved state
- Reconnecting clients receive any missed updates
Undo/Redo
Yjs supports collaborative undo with per-user stacks:
import { UndoManager } from 'yjs';
const yText = doc.getText('content');
const undoManager = new UndoManager(yText);
// Undo the last change (only yours)
undoManager.undo();
// Redo
undoManager.redo();
Offline Support
Changes made offline are queued and synced when reconnecting:
const { status, pendingChanges } = useDocument(room, 'main');
if (status === 'offline') {
return <div>Offline - {pendingChanges} changes pending</div>;
}