Operand

do no harem.

gram: docs

> ./examples/collaboration/README.md

# docx-editor — Realtime Collaboration
A minimal demo of multi-user collaborative editing on top of `@eigenpal/docx-editor-react` using [Yjs](https://yjs.dev), [`y-prosemirror`](https://github.com/yjs/y-prosemirror), and [`y-webrtc`](https://github.com/yjs/y-webrtc).
**No backend required.** Peers find each other through Yjs's public WebRTC signaling servers and sync directly browser-to-browser.
## Try it
```bash
bun install
bun run dev

Open http://localhost:5273, then click Share link and paste the URL into a second browser window. Type in either window — edits, selections, and avatars sync live.

How it works

Four pieces:

  1. externalContent prop tells the editor to treat its document prop as a schema seed only and skip the mount-time content load. ySyncPlugin populates ProseMirror from the shared Y.Doc instead.
  2. externalPlugins receives ySyncPlugin, yCursorPlugin(awareness), and yUndoPlugin() so Yjs owns the document state, remote cursors, and history. Tracked changes sync automatically through this — insertion/deletion mark attrs (author, date, revision id) ride along with the synced PM tree. Remote cursors and selection-range highlights also surface automatically via the editor's PM-decoration forwarding layer.
  3. Awareness (Yjs's ephemeral state channel) carries each user's name, color, and selection. The AvatarStack in the title bar reads provider.awareness.getStates() and renders connected users.
  4. Controlled comments prop + a Y.Array<Comment> on the same Y.Doc. PM only carries the comment range markers; the thread metadata (text, author, replies, resolved status) lives in the Y.Array, mirrored into React state and pushed back through onCommentsChange.
<DocxEditor
document={createEmptyDocument()} // schema seed only
externalContent // skip the load — Yjs owns content
externalPlugins={[ySync, yCursor, yUndo]}
comments={comments} // mirrored from Y.Array<Comment>
onCommentsChange={setComments} // writes back into Y.Array
author={user.name} // attribution for comments / track changes
renderTitleBarRight={() => <AvatarStack users={users} />}
/>

Files

File What it does
src/App.tsx Wires identity, room, collaboration hook, and renders DocxEditor
src/useCollaboration.ts Sets up Y.Doc, WebrtcProvider, awareness, the y-prosemirror plugins, and the comments Y.Array
src/AvatarStack.tsx Overlapping circular avatars in the title bar
src/identity.ts Per-tab user identity (sessionStorage) and room id from URL hash

Caveats

This is a demo, not a production-ready collab template. Known gaps: