Real-time Collaboration (Yjs)
Two editors bridged by Yjs — awareness gives you live cursors and the shared review ledger (comments, track changes,
AI suggestions all replicate). Pass textSync: true to also bind the HTML body to a shared Y.Text
so concurrent typing merges via CRDT instead of last-write-wins.
Alice
Welcome Alice. Type anything — Bob will see your cursor live.
Bob
Welcome Bob. You and Alice share the review ledger.
Example code
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
<script type="text/javascript" src="/richtexteditor/rte.js"></script>
<script type="text/javascript" src='/richtexteditor/plugins/all_plugins.js'></script>
<div style="display:grid; gap:14px; grid-template-columns:1fr; margin-top:10px;">
<div><strong>Alice</strong><div id="yjs_a"><p>Welcome Alice. Type anything — Bob will see your cursor live.</p></div></div>
<div><strong>Bob</strong><div id="yjs_b"><p>Welcome Bob. You and Alice share the review ledger.</p></div></div>
</div>
<script type="module">
// Peer-dependency imports — customers use npm or a provider of their choice.
import * as Y from "https://esm.sh/yjs@13.6.27";
import { Awareness } from "https://esm.sh/y-protocols@1.0.6/awareness?deps=yjs@13.6.27";
var edA = new RichTextEditor("#yjs_a", { commentsEnabled: true, trackChangesEnabled: true, currentUser: { id: "alice", name: "Alice", color: "#2563eb" } });
var edB = new RichTextEditor("#yjs_b", { commentsEnabled: true, trackChangesEnabled: true, currentUser: { id: "bob", name: "Bob", color: "#dc2626" } });
// Two Y.Docs bridged in-memory so this single-tab demo behaves like two browsers.
const docA = new Y.Doc(), docB = new Y.Doc();
const awA = new Awareness(docA), awB = new Awareness(docB);
docA.on("update", function (u, o) { if (o !== "remote") Y.applyUpdate(docB, u, "remote"); });
docB.on("update", function (u, o) { if (o !== "remote") Y.applyUpdate(docA, u, "remote"); });
function waitAttach(ed, opts) {
if (!ed.collab) { setTimeout(function () { waitAttach(ed, opts); }, 50); return; }
ed.collab.attach(opts);
}
waitAttach(edA, { doc: docA, provider: { awareness: awA }, user: { id: "alice", name: "Alice", color: "#2563eb" }, textSync: true });
waitAttach(edB, { doc: docB, provider: { awareness: awB }, user: { id: "bob", name: "Bob", color: "#dc2626" }, textSync: true });
</script>