WYSIWYG editing Image gallery upload Content templates
Real-time Collaboration (Yjs presence + shared review ledger)

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).

Alice Lee
Bob Chen
v1 (default) — Awareness + shared ledger

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().

v2 preview (opt-in) — Concurrent typing via Y.Text

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.

Production wiring

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
});

API

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