Search the Qalma docs

Type at least two characters to get started.

Docs

Mention

MentionPlugin detects a trigger such as @ada, exposes the active range to your UI, and inserts an inline mention node. It does not fetch users or render a menu.

import { MentionPlugin, createQalmaEditor } from '@qalma/editor';

const editor = createQalmaEditor({
  plugins: [MentionPlugin],
});

Public API

Contract Description
query<MentionState>('mention') Returns { from, to, query, trigger } while a mention query is active.
insertMention Replaces the active mention query or current selection with a mention node.
qalma-mention-update DOM event emitted from the editor view when mention state may have changed.
qalma-mention-keydown Cancelable DOM event for mention menu keys.

Mention keydown events cover ArrowDown, ArrowUp, Escape, Enter, Tab, space, and Spacebar.

Options

const editor = createQalmaEditor({
  plugins: [
    MentionPlugin.configure({
      trigger: '@',
      minQueryLength: 0,
      maxQueryLength: 64,
      appendSpaceOnInsert: true,
    }),
  ],
});
Option Default Validation
trigger '@' Single non-whitespace character.
minQueryLength 0 Non-negative integer.
maxQueryLength 64 Integer greater than or equal to minQueryLength.
appendSpaceOnInsert true Boolean.

Mentions are detected only when the selection is collapsed, the cursor is not inside a code block or inline code mark, the trigger starts the parent text or follows whitespace, and the query contains no whitespace.

Insert a mention

insertMention expects an object with id and label. The trigger is optional and defaults to the plugin trigger.

editor.execute('insertMention', {
  id: 'ada-lovelace',
  label: 'Ada Lovelace',
});

The mention serializes as a non-editable span:

<!-- prettier-ignore -->
<span
  data-qalma-mention
  data-mention-id="ada-lovelace"
  data-mention-label="Ada Lovelace"
  data-mention-trigger="@"
  contenteditable="false"
>
  @Ada Lovelace
</span>

Listen for the plugin events on the <qalma-content> host and read query state from the controller.

afterNextRender(() => {
  const surface = this.mentionSurface().nativeElement;

  const refresh = () => this.refreshMentions();
  const keydown = (event: Event) => this.handleMentionKeydown(event);

  surface.addEventListener('qalma-mention-update', refresh);
  surface.addEventListener('qalma-mention-keydown', keydown);

  this.destroyRef.onDestroy(() => {
    surface.removeEventListener('qalma-mention-update', refresh);
    surface.removeEventListener('qalma-mention-keydown', keydown);
  });
});
refreshMentions(): void {
  const mention = this.editor.query<MentionState>('mention');

  if (!mention) {
    this.suggestions.set([]);
    return;
  }

  this.suggestions.set(
    this.people.filter((person) =>
      person.label.toLowerCase().includes(mention.query.toLowerCase()),
    ),
  );
}

pick(person: { id: string; label: string }): void {
  this.editor.execute('insertMention', person);
}

If your menu handles a navigation key, call event.preventDefault() on the custom event. The plugin then prevents the original editor keydown.