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

# Collaboration

> Enable real-time collaborative editing using Yjs and Y.js providers

The Collaboration extension enables real-time collaborative editing in Tiptap using Yjs. It synchronizes content across multiple users and includes built-in undo/redo functionality that works seamlessly in collaborative environments.

<Note>
  The Collaboration extension comes with its own history implementation and is not compatible with the `@tiptap/extension-undo-redo` extension. Make sure to remove the UndoRedo extension if you're using Collaboration.
</Note>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @tiptap/extension-collaboration yjs
  ```

  ```bash yarn theme={null}
  yarn add @tiptap/extension-collaboration yjs
  ```

  ```bash pnpm theme={null}
  pnpm add @tiptap/extension-collaboration yjs
  ```
</CodeGroup>

You'll also need a Yjs provider to sync data between clients. Popular options include:

```bash theme={null}
npm install y-websocket  # WebSocket provider
npm install y-webrtc     # WebRTC provider
```

## Basic Usage

```javascript theme={null}
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'

// Create a Y.js document
const ydoc = new Y.Doc()

// Create a provider for syncing (WebSocket example)
const provider = new WebsocketProvider(
  'ws://localhost:1234',
  'document-name',
  ydoc
)

const editor = new Editor({
  extensions: [
    StarterKit.configure({
      // Disable the default history extension
      history: false,
    }),
    Collaboration.configure({
      document: ydoc,
    }),
  ],
})
```

## Configuration Options

<ParamField path="document" type="Y.Doc">
  An initialized Y.js document. This is the shared data structure that will be synchronized across all clients.

  **Example:**

  ```javascript theme={null}
  import * as Y from 'yjs'

  const ydoc = new Y.Doc()

  Collaboration.configure({
    document: ydoc,
  })
  ```
</ParamField>

<ParamField path="field" type="string">
  Name of the Y.js fragment to use. You can use different fields to sync multiple editors with one Y.js document.

  **Default:** `'default'`

  ```javascript theme={null}
  Collaboration.configure({
    document: ydoc,
    field: 'body', // Store editor content in 'body' field
  })

  // You could have another editor using the same document
  Collaboration.configure({
    document: ydoc,
    field: 'sidebar', // Store different content in 'sidebar' field
  })
  ```
</ParamField>

<ParamField path="fragment" type="XmlFragment">
  A raw Y.js fragment. Use this instead of `document` and `field` if you want direct control over the fragment.

  ```javascript theme={null}
  const ydoc = new Y.Doc()
  const fragment = ydoc.getXmlFragment('custom-fragment')

  Collaboration.configure({
    fragment: fragment,
  })
  ```
</ParamField>

<ParamField path="provider" type="any">
  The collaboration provider instance (e.g., WebsocketProvider, WebrtcProvider). While not required by the extension itself, storing it here makes it accessible via the extension.

  **Default:** `null`

  ```javascript theme={null}
  import { WebsocketProvider } from 'y-websocket'

  const provider = new WebsocketProvider('ws://localhost:1234', 'doc', ydoc)

  Collaboration.configure({
    document: ydoc,
    provider: provider,
  })
  ```
</ParamField>

<ParamField path="onFirstRender" type="() => void">
  Callback fired when the content from Yjs is initially rendered to Tiptap. Useful for showing a loading state until the document is ready.

  ```javascript theme={null}
  Collaboration.configure({
    document: ydoc,
    onFirstRender: () => {
      console.log('Document loaded and rendered')
      hideLoadingSpinner()
    },
  })
  ```
</ParamField>

<ParamField path="ySyncOptions" type="object">
  Options passed to the Y.js sync plugin. See [y-prosemirror documentation](https://github.com/yjs/y-prosemirror) for available options.

  ```javascript theme={null}
  Collaboration.configure({
    document: ydoc,
    ySyncOptions: {
      colors: [
        { light: '#ecd44433', dark: '#ecd444' },
        { light: '#ee635233', dark: '#ee6352' },
      ],
    },
  })
  ```
</ParamField>

<ParamField path="yUndoOptions" type="object">
  Options passed to the Y.js undo plugin.

  ```javascript theme={null}
  Collaboration.configure({
    document: ydoc,
    yUndoOptions: {
      trackedOrigins: new Set([ydoc.clientID]),
    },
  })
  ```
</ParamField>

## Commands

<ParamField path="undo" type="command">
  Undo recent changes.

  **Keyboard shortcut:** `Cmd/Ctrl + Z`

  ```javascript theme={null}
  editor.commands.undo()
  ```
</ParamField>

<ParamField path="redo" type="command">
  Reapply reverted changes.

  **Keyboard shortcuts:** `Cmd/Ctrl + Shift + Z` or `Cmd/Ctrl + Y`

  ```javascript theme={null}
  editor.commands.redo()
  ```
</ParamField>

## Storage

<ParamField path="isDisabled" type="boolean">
  Whether collaboration is currently disabled. This is automatically set when collaboration encounters a content error.

  ```javascript theme={null}
  // Check if collaboration is disabled
  if (editor.storage.collaboration.isDisabled) {
    console.log('Collaboration has been disabled')
  }
  ```
</ParamField>

## Advanced Examples

### Complete Collaborative Editor

```javascript theme={null}
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import Collaboration from '@tiptap/extension-collaboration'
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'

const ydoc = new Y.Doc()

const provider = new WebsocketProvider(
  'ws://localhost:1234',
  'my-document',
  ydoc
)

const editor = new Editor({
  extensions: [
    StarterKit.configure({
      history: false, // Important: disable default history
    }),
    Collaboration.configure({
      document: ydoc,
    }),
    CollaborationCursor.configure({
      provider: provider,
      user: {
        name: 'John Doe',
        color: '#f783ac',
      },
    }),
  ],
})
```

### Multiple Editors with One Document

```javascript theme={null}
const ydoc = new Y.Doc()
const provider = new WebsocketProvider('ws://localhost:1234', 'doc', ydoc)

// Main editor
const mainEditor = new Editor({
  element: document.querySelector('#main-editor'),
  extensions: [
    StarterKit.configure({ history: false }),
    Collaboration.configure({
      document: ydoc,
      field: 'main',
    }),
  ],
})

// Sidebar editor
const sidebarEditor = new Editor({
  element: document.querySelector('#sidebar-editor'),
  extensions: [
    StarterKit.configure({ history: false }),
    Collaboration.configure({
      document: ydoc,
      field: 'sidebar',
    }),
  ],
})
```

### Loading State

```javascript theme={null}
let isDocumentLoaded = false

const editor = new Editor({
  editable: false, // Start in read-only mode
  extensions: [
    StarterKit.configure({ history: false }),
    Collaboration.configure({
      document: ydoc,
      onFirstRender: () => {
        isDocumentLoaded = true
        editor.setEditable(true)
        hideLoadingSpinner()
      },
    }),
  ],
})

showLoadingSpinner()
```

### Content Error Handling

```javascript theme={null}
const editor = new Editor({
  enableContentCheck: true,
  extensions: [
    StarterKit.configure({ history: false }),
    Collaboration.configure({
      document: ydoc,
    }),
  ],
  onContentError: ({ editor, error, disableCollaboration }) => {
    console.error('Content validation error:', error)
    
    // Option 1: Disable collaboration to prevent further issues
    disableCollaboration()
    
    // Option 2: Show error to user
    showErrorNotification(
      'Document contains invalid content. Collaboration has been disabled.'
    )
    
    // Option 3: Attempt recovery
    editor.commands.setContent('<p>Content was reset due to an error</p>')
  },
})
```

### Custom Provider Setup

```javascript theme={null}
import { WebrtcProvider } from 'y-webrtc'

const ydoc = new Y.Doc()

// WebRTC provider for peer-to-peer collaboration
const provider = new WebrtcProvider('my-document', ydoc, {
  signaling: ['wss://signaling.example.com'],
  password: 'optional-room-password',
})

const editor = new Editor({
  extensions: [
    StarterKit.configure({ history: false }),
    Collaboration.configure({
      document: ydoc,
      provider: provider,
    }),
  ],
})

// Clean up on unmount
window.addEventListener('beforeunload', () => {
  provider.destroy()
  ydoc.destroy()
})
```

### Custom Undo/Redo Tracking

```javascript theme={null}
Collaboration.configure({
  document: ydoc,
  yUndoOptions: {
    // Only track changes from this user
    trackedOrigins: new Set([ydoc.clientID]),
    // Capture timeout in ms
    captureTimeout: 500,
  },
})
```

## Keyboard Shortcuts

| Shortcut               | Command | Description                 |
| ---------------------- | ------- | --------------------------- |
| `Cmd/Ctrl + Z`         | undo    | Undo the last change        |
| `Cmd/Ctrl + Shift + Z` | redo    | Redo the last undone change |
| `Cmd/Ctrl + Y`         | redo    | Redo the last undone change |

## Storage Access

```javascript theme={null}
// Check if collaboration is disabled
const isDisabled = editor.storage.collaboration.isDisabled

// Access the Y.js document
const ydoc = editor.extensionManager.extensions
  .find(ext => ext.name === 'collaboration')
  .options.document
```

## Utilities

The Collaboration extension adds utility methods to the editor:

```javascript theme={null}
// Get updated position after transaction
const newPosition = editor.utils.getUpdatedPosition(oldPosition, transaction)

// Create a mappable position that tracks across transactions
const mappablePos = editor.utils.createMappablePosition(position)
```

## Source Code

View the source code on GitHub:

* [Extension](https://github.com/ueberdosis/tiptap/tree/main/packages/extension-collaboration/src/collaboration.ts:87)
