useMentions Hook

The headless hook. Full control over rendering.

Import

import { useMentions } from "@skyastrall/mentions-react";

Return Value

Prop Type Default Description
editorRef RefObject<HTMLDivElement> Attach to your contenteditable div
inputProps object ARIA + event handlers for the editor
listProps object ARIA attributes for the suggestion list
getItemProps (index) => object ARIA + handlers for each item
isOpen boolean Whether the dropdown is visible
isLoading boolean Whether an async fetch is in progress
items MentionItem[] Current suggestion items
highlightedIndex number Highlighted item (-1 = none)
activeTrigger string | null Active trigger character
caretPosition CaretPosition | null Caret viewport coordinates
markup string Current markup string
plainText string Current plain text
mentions MentionItem[] All active mentions
handleInput () => void Call from editor's onInput
clear () => void Clears all content
focus () => void Focuses the editor
insertTrigger (trigger) => void Inserts trigger and opens dropdown

Usage

function CustomEditor() {
  const {
    editorRef, inputProps, listProps, getItemProps,
    isOpen, items, highlightedIndex, caretPosition, handleInput,
  } = useMentions({
    triggers: [{ char: "@", data: users }],
    onChange: (markup, plainText) => console.log(markup),
  });

  return (
    <div data-mentions="" style={{ position: "relative" }}>
      <div
        ref={editorRef}
        contentEditable="plaintext-only"
        onInput={handleInput}
        data-mentions-editor=""
        {...inputProps}
        style={{ outline: "none", whiteSpace: "pre-wrap", padding: 12 }}
      />
      {isOpen && items.length > 0 && (
        <ul
          {...listProps}
          style={{
            position: "fixed",
            top: (caretPosition?.top ?? 0) + (caretPosition?.height ?? 0) + 4,
            left: caretPosition?.left ?? 0,
          }}
        >
          {items.map((item, i) => (
            <li
              key={item.id}
              {...getItemProps(i)}
              style={{
                padding: "8px 12px",
                background: i === highlightedIndex ? "#f1f5f9" : "white",
                cursor: "pointer",
              }}
            >
              {item.label}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

The editor needs data-mentions="" on a parent and data-mentions-editor="" on itself for blur handling and placeholder CSS to work correctly.