EditorMentionMenu

GitHub
A mention menu that displays user suggestions when typing the @ character in the editor.

Usage

Examples

API

Props

Prop Default Type
editorEditor
char'@' string

The trigger character (e.g., '/', '@', ':')

pluginKey'mentionMenu' string

Plugin key to identify this menu

items EditorMentionMenuItem[] | EditorMentionMenuItem[][]

The items to display (can be a flat array or grouped)

limit42 number

Maximum number of items to display

options{ strategy: 'absolute', placement: 'bottom-start', offset: 8 } FloatingUIOptions

The options for positioning the menu. Those are passed to Floating UI and include options for the placement, offset, flip, shift, size, autoPlacement, hide, and inline middleware.

appendTo HTMLElement | (): HTMLElement

The DOM element to append the menu to. Default is the editor's parent element.

Sometimes the menu needs to be appended to a different DOM context due to accessibility, clipping, or z-index issues.

ui { content?: ClassNameValue; viewport?: ClassNameValue; group?: ClassNameValue; label?: ClassNameValue; separator?: ClassNameValue; item?: ClassNameValue; itemLeadingIcon?: ClassNameValue; itemLeadingAvatar?: ClassNameValue; itemLeadingAvatarSize?: ClassNameValue; itemWrapper?: ClassNameValue; itemLabel?: ClassNameValue; itemDescription?: ClassNameValue; itemLabelExternalIcon?: ClassNameValue; }

Slots

Slot Type

Emits

Event Type

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    editorMentionMenu: {
      slots: {
        content: 'min-w-48 max-h-96 bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-dropdown-menu-content-transform-origin) flex flex-col',
        viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1',
        group: 'p-1 isolate',
        label: 'w-full flex items-center font-semibold text-highlighted p-1.5 text-xs gap-1.5',
        separator: '-mx-1 my-1 h-px bg-border',
        item: 'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 p-1.5 text-sm gap-1.5',
        itemLeadingIcon: 'shrink-0 size-5 flex items-center justify-center text-base',
        itemLeadingAvatar: 'shrink-0',
        itemLeadingAvatarSize: '2xs',
        itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
        itemLabel: 'truncate',
        itemDescription: 'truncate text-muted',
        itemLabelExternalIcon: 'inline-block size-3 align-top text-dimmed'
      },
      variants: {
        active: {
          true: {
            item: 'text-highlighted before:bg-elevated/75',
            itemLeadingIcon: 'text-default'
          },
          false: {
            item: [
              'text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            itemLeadingIcon: [
              'text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
              'transition-colors'
            ]
          }
        }
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        editorMentionMenu: {
          slots: {
            content: 'min-w-48 max-h-96 bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-dropdown-menu-content-transform-origin) flex flex-col',
            viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1',
            group: 'p-1 isolate',
            label: 'w-full flex items-center font-semibold text-highlighted p-1.5 text-xs gap-1.5',
            separator: '-mx-1 my-1 h-px bg-border',
            item: 'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 p-1.5 text-sm gap-1.5',
            itemLeadingIcon: 'shrink-0 size-5 flex items-center justify-center text-base',
            itemLeadingAvatar: 'shrink-0',
            itemLeadingAvatarSize: '2xs',
            itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
            itemLabel: 'truncate',
            itemDescription: 'truncate text-muted',
            itemLabelExternalIcon: 'inline-block size-3 align-top text-dimmed'
          },
          variants: {
            active: {
              true: {
                item: 'text-highlighted before:bg-elevated/75',
                itemLeadingIcon: 'text-default'
              },
              false: {
                item: [
                  'text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
                  'transition-colors before:transition-colors'
                ],
                itemLeadingIcon: [
                  'text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
                  'transition-colors'
                ]
              }
            }
          }
        }
      }
    })
  ]
})

Changelog

No recent changes