Documentation

Collaboration & Review

Collaboration & Review plugins

Six plugins that turn the editor into a real-world document workflow: slash commands, @mentions, Track Changes, threaded comments, revision history, and Yjs-backed presence. All ship in the standard license — no premium SKU required.

Slash commands

Type / on an empty line (or after whitespace) to open an inline command picker. 15 built-in blocks (H1–H3, bullet / numbered lists, quote, code, divider, table, image, link, emoji, today’s date) plus every registered AI Toolkit action.

Config

{
    slashCommandEnabled: true,          // default when this plugin is loaded
    slashCommandIncludeAi: true         // pull aiToolkitActions into the menu
}

API

editor.slashCommands.register({ id, label, keywords, run });
editor.slashCommands.remove(id);
editor.slashCommands.list();
editor.slashCommands.open(); / .close();

@Mentions

Trigger-character framework for @, #, [[wiki]], or any custom prefix. Async data sources (debounced, with a loading state). Atomic non-editable pills — backspace removes the whole chip.

Register a trigger

editor.mentions.register({
    trigger: "@",
    insertClass: "rte-mention-person",
    search: function (query, done) {
        fetch("/api/users?q=" + encodeURIComponent(query))
            .then(r => r.json())
            .then(done);                // Array<{ id, name, color? }>
    },
    renderItem: function (user) { return user.name; },
    renderInsert: function (user) { return "@" + user.name; }
});

Track Changes (human suggesting mode)

Word-style suggesting. Insertions appear underlined in the current user’s color; deletions get a strikethrough (not removed until accepted). Sequential deletes merge into one span; backspacing inside your own just-typed insert shrinks it.

Config

{
    trackChangesEnabled: true,
    currentUser: { id: "maya", name: "Maya Patel", color: "#9333ea" }
}

Per-author accept / reject from the Review drawer. Works alongside AI suggestions — both end up in the same editor.reviewLedger store.

Threaded comments

Comments anchor to selection ranges and render as a highlight + sidebar thread. Composer, replies, resolve, delete.

Config

{
    commentsEnabled: true,
    currentUser: { id: "alice", name: "Alice Lee", color: "#2563eb" }
}

API

editor.comments.add(range, text);
editor.comments.reply(threadId, text);
editor.comments.resolve(threadId);
editor.comments.delete(threadId);
editor.comments.list();

Revision history

Snapshot browser with a sandboxed preview iframe and an LCS-based line diff. Manual or debounced auto-snapshots. localStorage by default, or POST to a server endpoint.

Config

{
    revisionHistoryEnabled: true,
    revisionHistoryMaxEntries: 50,
    revisionHistoryAutoSnapshotMs: 10000,
    revisionHistoryUrl: "/api/revisions"        // optional
}

API

editor.revisionHistory.snapshot(label?, metadata?);
editor.revisionHistory.promptAndSnapshot(defaultLabel?);   // native prompt + snapshot
editor.revisionHistory.rename(id, label);
editor.revisionHistory.list();                             // all snapshots
editor.revisionHistory.listNamed();                        // user-labeled only
editor.revisionHistory.diff(idA, idB);                     // { lines, oldText, newText }
editor.revisionHistory.restore(id);
editor.revisionHistory.delete(id);
editor.revisionHistory.openBrowser();

Yjs presence & concurrent typing

Live cursors, presence avatars, shared review ledger. Yjs is a peer dependency — the plugin never ships it. You load Yjs + a provider (WebSocket / WebRTC / Hocuspocus) and pass them in.

Attach

import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";

const ydoc = new Y.Doc();
const provider = new WebsocketProvider("wss://collab.example.com", docId, ydoc);

editor.collab.attach({
    doc: ydoc,
    provider: provider,
    user: { id: "alice", name: "Alice", color: "#2563eb" },
    textSync: true          // opt-in concurrent typing via shared Y.Text
});

textSync (preview). When enabled, the editor’s HTML is mirrored into a Y.Text. Concurrent inserts / deletes merge via CRDT. Tradeoffs: remote updates re-set the body (caret snaps to start), HTML character offsets don’t align with rendered caret positions. Per-node binding (y-xml-fragment) is on the roadmap.

Shared review ledger

AI suggestions, human tracked-change suggestions, and comments all funnel through a single store: editor.reviewLedger. That’s how the Review drawer can show them interleaved and accept / reject works the same way regardless of source.

API

editor.reviewLedger.add(entry);            // { id, changeType, author, text, replies[], ... }
editor.reviewLedger.update(id, patch);
editor.reviewLedger.remove(id);
editor.reviewLedger.get(id);
editor.reviewLedger.list();
editor.reviewLedger.refreshPanel();