Manage threads in your editor

Use this guide to integrate comments directly into your editor. For a complete list of all Comments editor commands, see the Editor Commands page.

You can also interact with comments from outside your editor via our Comments REST API.

Learn about threads

Tiptap's Comments feature organizes discussions into threads, enabling clear and context-relevant collaboration by distinguishing between threads and individual comments.

Threads serve as containers for discussions related to specific document sections, while comments represent individual contributions within those threads.

Create a new thread

Let's assume you have a button to create a new thread. You can use the setThread command to create a new thread at the current selection.

const createThread = () => {
  editor
    .chain()
    .setThread({
      content: 'This is a new thread', // the content of the threads first inital comment
    })
    .run()
}

This will create a new thread at the current selection and add a comment with the given content. By default comments and threads don't have a user or any other metadata assigned. Let's say you want to add the author to the thread and the comment. You can do this by passing through the data and commentData property to the setThread command.

const createThread = () => {
  const user = {
    id: '123', // the user id of the author
    name: 'John Doe', // the name of the author
    avatarUrl: 'https://example.com/avatar.jpg', // the avatar of the author
  }

  editor
    .chain()
    .setThread({
      content: 'This is a new thread', // the content of the threads first inital comment
      data: {
        user,
      },
      commentData: {
        user,
      },
    })
    .run()
}

Now the thread and comment will have a user assigned to it.

Receive and watch threads and comments

Receiving and watching the threads on your current document can easily be done by using the subscribeToThreads function. This function will register a watcher, fetch the first initial list of threads and keep the list up to date.

To unsubscribe from the threads, you can call the callback function returned by the subscribeToThreads function.

// Subscribe to threads
const unsubscribe = subscribeToThreads({
  provider: yourTiptapCollabProvider,
  callback: (threads) => {
    // do something with threads, store in a state or variable from here
  },
  // optional options
  getThreadsOptions: {
    // only threads with the specific type will be fetched/watched, possible values are 'archived' and 'unarchived',
    // if not set, only unarchived threads will be handled
    // archived and unarchived threads represent soft-deleted threads
    types: ['archived', 'unarchived'],
  },
})

Receive and render threads manually

To receive the list of threads on your current document manually, you can simply call provider.getThreads(). This will return an array of threads on the document connected to your provider.

This is a static array which won't update on its own. If you want to keep the list of threads up to date, you can listen to changes via the provider.watchThreads and provider.unwatchThreads functions.

// let's save threads in a variable
let threads = []

// this function is called whenever the threads change
const getThreads = () => {
  threads = provider.getThreads()
}

// initial call to get the threads
getThreads()

// watch for changes
provider.watchThreads(getThreads)

To unwatch the threads you can call provider.unwatchThreads(getThreads).

provider.unwatchThreads(getThreads)

Let's say you want to write a react hook to get the threads and keep them up to date, you could write a hook like this.

const useThreads = (provider) => {
  const [threads, setThreads] = useState([])

  useEffect(() => {
    if (!provider) {
      return () => null
    }

    const getThreads = () => {
      setThreads(provider.getThreads())
    }

    getThreads()

    provider.watchThreads(getThreads)

    return () => {
      provider.unwatchThreads(getThreads)
    }
  }, [provider])

  return threads
}

Now those threads will be reactive and can be used to render the threads in your UI.

Update a thread

To update a thread you can use the updateThread command. This command will update the thread with the given id and update the content of the thread.

editor.commands.updateThread({
  id: '123',
  {
    data: {
      seen: true,
    }
  }
})

This will update the thread with the ID 123 and set the seen property to true.

Delete a thread

To delete a thread you can use the removeThread command. This command will delete the thread with the given ID.

How to delete threads

By default, threads removed won't be deleted from the yjs document. To do this, you can pass through the deleteThread option to the removeThread command.

editor.commands.removeThread({
  id: '123',
  deleteThread: true,
})

Create, update and delete comments

Comments can be added, edited, and removed within threads but cannot be marked as resolved, as they are considered parts of the thread discussions.

To create a comment on a thread you can use the createComment command. This command will create a new comment on the thread with the given ID.

editor.commands.createComment({
  threadId: '123',
  content: 'This is a new comment', // this could also be tiptap JSON or any other type of content
  data: {
    user, // pass through any meta data you want - in this case the user
  },
})

This will create a new comment on the thread with the ID 123 and set the content to This is a new comment. You can also pass through any metadata you want to the comment.

To update a comment you can use the updateComment command. This command will update the comment with the given ID and update the content of the comment.

editor.commands.updateComment({
  threadId: '123', // the thread ID
  id: '456', // the comment ID
  content: 'Now this is the new content', // the new content of the comment
  data: {
    edited: true, // set the edited property to true
  },
})

This will update the comment with the ID 456 on the thread with the ID 123 and set the content to Now this is the new content. You can also pass through any metadata you want to the comment.

Finally you can delete a comment by using the deleteComment command. This command will delete the comment with the given ID.

editor.commands.deleteComment({
  threadId: '123',
  id: '456',
})

Resolve and unresolve threads

To resolve a thread you can use the resolveThread command. This command will resolve the thread with the given ID.

editor.commands.resolveThread({
  id: '123',
})

This will resolve the thread with the ID 123. To unresolve a thread you can use the unresolveThread command. This command will unresolve the thread with the given ID.

If you want to resolve a thread and add information on which user resolved the thread, you can set the threads data to include the user who resolved the thread. Be sure to clear the data when unresolving the thread.

editor.commands.unresolveThread({
  id: '123',
})

Select a thread

To select a thread you can use the selectThread command. This command selects the thread with the specified ID.

editor.commands.selectThread({
  id: '123',
})

This will move the cursor to the thread with the ID 123.

To deselect a thread you can use the unselectThread command. This command deselects the thread with the specified ID.

editor.commands.unselectThread({
  id: '123',
})

You can also select or unselect threads without ID. In that case, the editor will select or unselect the thread at the current selection.