Mention extension

VersionDownloads

Honestly, the mention node is amazing. It adds support for @mentions, for example to ping users, and provides full control over the rendering.

Literally everything can be customized. You can pass a custom component for the rendering. All examples use .filter() to search through items, but feel free to send async queries to an API or add a more advanced library like fuse.js to your project.

Install

npm install @tiptap/extension-mention

Dependencies

Since 2.0.0-beta.193 we marked the @tiptap/suggestion as a peer dependency. That means, you will need to install it manually.

npm install @tiptap/suggestion

Settings

HTMLAttributes

Custom HTML attributes that should be added to the rendered HTML tag.

Mention.configure({
  HTMLAttributes: {
    class: 'my-custom-class',
  },
})

renderText

Define how a mention text should be rendered.

Mention.configure({
  renderText({ options, node }) {
    return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`
  },
})

renderHTML

Define how a mention html element should be rendered, this is useful if you want to render an element other than span (e.g a)

Mention.configure({
  renderHTML({ options, node }) {
    return [
      'a',
      mergeAttributes({ href: '/profile/1' }, options.HTMLAttributes),
      `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`,
    ]
  },
})

deleteTriggerWithBackspace

Toggle whether the suggestion character(s) should also be deleted on deletion of a mention node. Default is false.

Mention.configure({
  deleteTriggerWithBackspace: true,
})

suggestion

Options for the Suggestion utility. Used to define what character triggers the suggestion popup, among other parameters. Read more.

Mention.configure({
  suggestion: {
    // …
  },
})

suggestions

Allows you to define multiple types of mentions within the same editor. For example, define a mention for people with the @ trigger and one for movies with the # trigger. Read more about the Suggestion utility.

Mention.configure({
  suggestions: [
    {
      char: '@',
      // Other options of the Suggestion utility
    },
    {
      char: '#',
      // Other options of the Suggestion utility
    },
  ],
})

Below is an example demo:

Collaboration

When working with Tiptap Collaboration, suggestions can sometimes "pop open" for remote users when someone else is typing a mention. To prevent this, you can configure the shouldShow option:

import { Mention } from '@tiptap/extension-mention'
import { isChangeOrigin } from '@tiptap/extension-collaboration'

const Editor = new Editor({
  extensions: [
    Mention.configure({
      suggestion: {
        shouldShow: ({ transaction }) => isChangeOrigin(transaction),
      },
    }),
  ],
})

This ensures that the suggestion menu only opens for the user who actually typed the trigger character.

Use in Vanilla JavaScript

Here is a complete example that sets up a mention with a suggestion list:

import { Editor } from '@tiptap/core'
import Mention from '@tiptap/extension-mention'

new Editor({
  element: document.querySelector('#editor'),
  extensions: [
    StarterKit,
    Mention.configure({
      HTMLAttributes: {
        class: 'mention',
      },
      suggestion: {
        char: '@',
        items: ({ query }) => {
          return ['Alice', 'Bob', 'Carol'].filter((name) =>
            name.toLowerCase().includes(query.toLowerCase())
          )
        },
        render: () => {
          let popup

          return {
            onStart: (props) => {
              popup = document.createElement('div')
              popup.classList.add('suggestion-popup')
              props.items.forEach((item) => {
                const button = document.createElement('button')
                button.textContent = item
                button.addEventListener('click', () => props.command({ id: item }))
                popup.appendChild(button)
              })
              document.body.appendChild(popup)
            },
            onUpdate: (props) => {
              popup.innerHTML = ''
              props.items.forEach((item) => {
                const button = document.createElement('button')
                button.textContent = item
                button.addEventListener('click', () => props.command({ id: item }))
                popup.appendChild(button)
              })
            },
            onHide: () => {
              popup?.remove()
            },
          }
        },
      },
    }),
  ],
  content: '<p>Type @ to mention someone.</p>',
})

You can also pass a custom React or Vue component for rendering. See the Suggestion utility for details.

Source code

packages/extension-mention/