2 – Concurrent Editing in TipTap


In the first blog post in this series, we set up a basic Tiptap editor. Today, let’s enhance the editor by integrating real-time, concurrent editing capabilities using Yjs, a powerful CRDT library for shared editing, and the y-webrtc connector for peer-to-peer communication.

Initial Setup

Let’s start by examining the initial Tiptap setup without concurrent editing capabilities:

<script setup lang="ts">
import * as Y from "yjs";
import { EditorContent, useEditor } from "@tiptap/vue-3";
import StarterKit from "@tiptap/starter-kit";

const editor = useEditor({
  content: `
    <h2>
      Hello World!
    </h2>
  `,
  extensions: [
    StarterKit,
  ],
});
</script>

<template>
  <EditorContent :editor="editor" />
</template>

In this setup, we have a basic Tiptap editor with an initial content of “Hello World!”. Now, let’s enhance this setup to support real-time collaborative editing.

Adding Real-Time Collaboration

To add collaborative editing features, we need to integrate Yjs and its WebRTC provider. Yjs is a framework for real-time collaborative editing using CRDTs (Conflict-free Replicated Data Types), which ensure consistency across all clients without the need for a central server once connections are established.

Step-by-Step Integration

  1. Install Necessary Packages: First, install the additional npm packages required for collaboration:
npm install @tiptap/extension-collaboration @tiptap/extension-collaboration-cursor y-webrtc

2. Update the Editor Configuration: Modify your Tiptap setup to import the collaboration extensions. Here’s how you do it:

<script setup lang="ts">
import * as Y from "yjs"
import {EditorContent, useEditor} from "@tiptap/vue-3"
import StarterKit from "@tiptap/starter-kit"
import {Collaboration} from "@tiptap/extension-collaboration";
import {WebrtcProvider} from "y-webrtc"
import {CollaborationCursor} from "@tiptap/extension-collaboration-cursor";

...

</script>

3.Update your code to add the new extensions to the tiptap editor. In the code snippet below, we are faking different authenticated user accounts using the Math.random() function.

const ydoc = new Y.Doc();
const provider = new WebrtcProvider("tiptap-test", ydoc);
const editor = useEditor({
  content: `
    <h2>
      Hello World!
    </h2>
  `,
  extensions: [
    StarterKit,
    Collaboration.configure({
      document: ydoc,
    }),
    CollaborationCursor.configure({
      provider: provider,
      user: {
        name: `User ${Math.floor(Math.random() * 100)}`,
        color: `#${Math.floor(Math.random() * 16777215).toString(16)}`
      }
    }),
  ],
})

4. Add some scss styles (from the collaboration extension’s page) to appropriately style the concurrent editor’s cursor.

/* Placeholder (at the top) */
.tiptap p.is-editor-empty:first-child::before {
  color: #adb5bd;
  content: attr(data-placeholder);
  float: left;
  height: 0;
  pointer-events: none;
}

/* Give a remote user a caret */
.collaboration-cursor__caret {
  border-left: 1px solid #0d0d0d;
  border-right: 1px solid #0d0d0d;
  margin-left: -1px;
  margin-right: -1px;
  pointer-events: none;
  position: relative;
  word-break: normal;
}

/* Render the username above the caret */
.collaboration-cursor__label {
  border-radius: 3px 3px 3px 0;
  color: #0d0d0d;
  font-size: 12px;
  font-style: normal;
  font-weight: 600;
  left: -1px;
  line-height: normal;
  padding: 0.1rem 0.3rem;
  position: absolute;
  top: -1.4em;
  user-select: none;
  white-space: nowrap;
}

Explanation of Changes

  • Y.Doc: A Yjs document that holds the shared data.
  • WebrtcProvider: Initializes a WebRTC provider for peer-to-peer communication, using "tiptap-test" as a room name where all instances connect and sync.
  • Collaboration: A Tiptap extension configured to sync the editor state through the shared Yjs document.
  • CollaborationCursor: Shows cursor positions and selections of other users in real-time. Each user is assigned a random name and color.

Running Your Enhanced Editor

To see the collaborative editor in action, run your Vue application:

yarn run dev

Open multiple browser tabs or different browsers and point them to your local server. You should be able to type in one tab and see the changes reflected in real-time across all other tabs.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *