All configuration options, events, and hooks for real-time collaboration.
Collaboration Config
You manage the Yjs provider - works with SuperDoc Yjs, Liveblocks, Hocuspocus, etc.
import * as Y from "yjs";
import { LiveblocksYjsProvider } from "@liveblocks/yjs";
const ydoc = new Y.Doc();
const provider = new LiveblocksYjsProvider(room, ydoc);
new SuperDoc({
selector: "#editor",
modules: {
collaboration: { ydoc, provider },
},
});
modules.collaboration.ydoc
Your Yjs document instance
modules.collaboration.provider
Any Yjs-compatible provider
User Configuration
Current user information for presence/awarenessuser: {
name: 'John Smith',
email: '[email protected]',
image: 'https://example.com/avatar.jpg' // Optional
}
Color palette for user cursors and selectionscolors: ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"];
Users are automatically assigned colors from this palette.
Events
onReady
Fired when SuperDoc and collaboration are fully initialized.
new SuperDoc({
// ...config
onReady: ({ superdoc }) => {
console.log("Ready!");
// Access Yjs document
const ydoc = superdoc.ydoc;
// Access active editor
const editor = superdoc.activeEditor;
},
});
onAwarenessUpdate
Fired when users join, leave, or update their presence.
new SuperDoc({
// ...config
onAwarenessUpdate: ({ states, added, removed, superdoc }) => {
// All connected users
const users = states.filter((s) => s.user);
// Users who just joined
added.forEach((clientId) => {
const user = states.find((s) => s.clientId === clientId);
console.log("User joined:", user?.name);
});
// Users who just left
removed.forEach((clientId) => {
console.log("User left:", clientId);
});
},
});
User state properties:
| Property | Type | Description |
|---|
clientId | number | Unique session ID |
name | string | User’s display name |
email | string | User’s email |
color | string | Assigned cursor color |
cursor | Object | Current cursor position |
selection | Object | Current text selection |
onEditorCreate
Fired when an editor instance is created.
new SuperDoc({
// ...config
onEditorCreate: ({ editor }) => {
// Check if document is empty
const isEmpty = !editor.state.doc.textContent.trim();
if (isEmpty) {
// Load default content
await editor.replaceFile(defaultDocument);
}
}
});
onContentError
Fired when document content fails to load.
new SuperDoc({
// ...config
onContentError: ({ error, documentId }) => {
console.error("Failed to load:", documentId, error);
showErrorMessage("Document could not be loaded");
},
});
Provider Events
When using the provider-agnostic API, listen to provider events directly:
// Sync status
provider.on("sync", (synced) => {
if (synced) console.log("Document synced");
});
// For Hocuspocus/URL-based
provider.on("status", ({ status }) => {
// 'connecting' | 'connected' | 'disconnected'
updateConnectionIndicator(status);
});
provider.on("authenticationFailed", ({ reason }) => {
if (reason === "token-expired") {
refreshToken();
}
});
Handle image uploads in collaborative documents:
new SuperDoc({
// ...config
handleImageUpload: (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const dataUrl = event.target.result;
const mediaPath = `word/media/${file.name}`;
// Store in Yjs for sync
if (superdoc.ydoc) {
const mediaMap = superdoc.ydoc.getMap("media");
mediaMap.set(mediaPath, dataUrl);
}
resolve(dataUrl);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
},
});
SuperEditor Usage
For direct SuperEditor usage (without SuperDoc wrapper):
import { Editor } from "superdoc/super-editor";
const editor = new Editor({
element: document.querySelector("#editor"),
ydoc: ydoc,
collaborationProvider: provider,
user: { name: "John", email: "[email protected]" },
});
SuperEditor is the lower-level editor component. Most users should use
SuperDoc, which provides document loading, toolbar, and additional features.
Complete Example
import { createClient } from "@liveblocks/client";
import { LiveblocksYjsProvider } from "@liveblocks/yjs";
import * as Y from "yjs";
import { SuperDoc } from "superdoc";
const client = createClient({ publicApiKey: "pk_..." });
const { room, leave } = client.enterRoom("my-document");
const ydoc = new Y.Doc();
const provider = new LiveblocksYjsProvider(room, ydoc);
let superdoc = null;
provider.on("sync", (synced) => {
if (!synced) return;
superdoc = new SuperDoc({
selector: "#editor",
documentMode: "editing",
user: {
name: "John Smith",
email: "[email protected]",
},
colors: ["#FF6B6B", "#4ECDC4", "#45B7D1"],
modules: {
collaboration: { ydoc, provider },
},
onReady: ({ superdoc }) => {
console.log("Collaboration ready");
},
onAwarenessUpdate: ({ states }) => {
const users = states.filter((s) => s.user);
renderUserList(users);
},
onContentError: ({ error }) => {
console.error("Content error:", error);
},
});
});
// Cleanup
window.addEventListener("beforeunload", () => {
superdoc?.destroy();
provider.destroy();
leave();
});