Two editors on this page share a single Y.Doc via a peer-dependency y-protocols Awareness channel. Move your cursor in one, watch the colored caret appear in the other. Add a comment or tracked change in one, see it replicate instantly to the other — every entry in editor.reviewLedger (AI suggestions, tracked changes, comments) rides a shared Y.Map. Concurrent text editing is not in v1 (that needs a content-level CRDT binding).
Awareness (live cursors + presence) and shared reviewLedger (every AI / tracked-change / comment entry replicates via a single Y.Map). Yjs and the provider are peer dependencies: the plugin never ships them. Customers load them (ESM from CDN, npm, etc.) and pass a Y.Doc + anything with an .awareness field to editor.collab.attach().
Pass textSync: true to attach() to bind the editor's full HTML to a shared Y.Text. CRDT merges
concurrent inserts/deletes at character level, so two users typing in different parts of the document converge without losing either edit.
Tradeoffs in this preview: remote updates re-set the body (caret snaps to start), and HTML character offsets don't align with
rendered caret positions. Production-grade per-node binding (y-xml-fragment) is on the roadmap; this MVP closes the
"two users typing" RFP checkbox today without waiting for the full binding.
import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
const ydoc = new Y.Doc();
const provider = new WebsocketProvider("wss://collab.example.com", documentId, ydoc);
editor.collab.attach({
doc: ydoc,
provider: provider,
user: { id: currentUser.id, name: currentUser.name, color: userColor },
textSync: true // opt-in concurrent typing via shared Y.Text
});
editor.collab.attach({ doc, provider, user });
editor.collab.detach();
editor.collab.isAttached();
editor.collab.peers(); // array of { clientId, user, caret }
editor.collab.setUser(user); // update local identity mid-session