> ## Documentation Index
> Fetch the complete documentation index at: https://docs.collab-kit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Collaborative Editor

> Build a real-time collaborative text editor with Yjs and TipTap.

This guide shows you how to build a Google Docs-style collaborative text editor using CollabKit's Yjs provider with TipTap.

## What You'll Build

* A rich text editor where multiple users can type simultaneously
* Conflict-free collaborative editing via CRDTs
* Persistent document state (survives page refreshes)
* User cursors and presence indicators

## Prerequisites

* A CollabKit server running with a room and users created
* `@collab-kit/client` installed

## Step 1: Install Dependencies

```bash theme={null}
npm install @collab-kit/client @collab-kit/utils yjs \
  @tiptap/core @tiptap/starter-kit @tiptap/extension-collaboration
```

## Step 2: Set Up CollabKit

```typescript theme={null}
import CollabKitClient from '@collab-kit/client';

const client = new CollabKitClient({
  serverUrl: 'https://api.collab-kit.com',
  authToken: '<jwt-token>',
});

await client.join({ role: 'editor' });
```

<Note>
  Yjs writes require an editor session. A viewer can load and receive document updates, but outbound Yjs changes are blocked.
</Note>

## Step 3: Create the Yjs Document and Provider

```typescript theme={null}
import { CollabKitYjsProvider } from '@collab-kit/client/yjs';
import * as Y from 'yjs';

const ydoc = new Y.Doc();
const provider = new CollabKitYjsProvider(client, ydoc, {
  documentId: 'main-editor', // Unique per document in the room
});
```

## Step 4: Initialize TipTap

```typescript theme={null}
import { Editor } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import Collaboration from '@tiptap/extension-collaboration';

const editor = new Editor({
  element: document.getElementById('editor'),
  extensions: [
    StarterKit.configure({
      history: false, // Disable built-in undo -- Yjs handles this
    }),
    Collaboration.configure({
      document: ydoc,
    }),
  ],
  editable: false, // Start disabled until synced
});

// Enable editing once the initial document state loads
provider.on('synced', () => {
  editor.setEditable(true);
  console.log('Document ready for editing');
});
```

<Warning>
  Always disable TipTap's built-in `history` extension when using Collaboration. Yjs provides its own undo/redo management that understands collaborative edits.
</Warning>

## Step 5: Add a Loading State

Show a loading indicator until the document syncs:

```typescript theme={null}
const loadingEl = document.getElementById('loading');

provider.on('synced', () => {
  loadingEl.style.display = 'none';
  editor.setEditable(true);
});
```

## Step 6: Add User Presence (Optional)

Show cursor positions of other users alongside the editor:

```typescript theme={null}
// Share cursor/selection position
editor.on('selectionUpdate', ({ editor }) => {
  const { from, to } = editor.state.selection;
  client.presence.update({
    cursor: { from, to },
    user: { name: client.currentUser?.name },
  });
});

// Display other users' selections
client.presence.sync('*', ({ userId, state }) => {
  if (userId === client.userId || !state) return;
  // Use state.cursor.from and state.cursor.to to highlight
  // their selection in the editor (implementation depends on your UI)
  console.log(`${state.user.name} is at position ${state.cursor.from}-${state.cursor.to}`);
});
```

## Step 7: Clean Up

```typescript theme={null}
window.addEventListener('beforeunload', () => {
  provider.destroy();
  editor.destroy();
  void client.disconnect();
});
```

## Multiple Documents Per Room

You can have multiple collaborative documents in the same room by using different `documentId` values:

```typescript theme={null}
const notesDoc = new Y.Doc();
const notesProvider = new CollabKitYjsProvider(client, notesDoc, {
  documentId: 'meeting-notes',
});

const agendaDoc = new Y.Doc();
const agendaProvider = new CollabKitYjsProvider(client, agendaDoc, {
  documentId: 'meeting-agenda',
});
```

## Next Steps

* Add [cursor tracking](/guides/cursor-tracking) alongside the editor
* Use [stores](/guides/real-time-stores) to save editor metadata (last editor, word count)
* Add [comments](/guides/comments-system) anchored to text selections
