API reference
Components, hooks, and editor transactions.
Root and channels
Mention.Root<T> and useMention<T>() accept:
| Prop | Purpose |
|---|---|
items | Array of items, or (query, signal) => Promise<readonly T[]>. |
getKey | Unique, stable string or number for each item. |
getLabel | Search label and default insertion label. |
allowSpaces | Allow horizontal spaces in this channel’s query. Defaults to false; tabs, line breaks, and editor atoms still stop detection. |
filter | Optional synchronous (item, query) => boolean for arrays. Defaults to case-insensitive label substring matching; fetcher results bypass it. |
trigger | One non-whitespace UTF-16 character; defaults to @. |
getInsertText | Optional (item, meta) => string. Defaults to trigger + label. |
onSelect | Optional notification after successful insertion. |
debounceMs | Async request delay, default 150 ms. Use 0 for immediate requests. |
A separating space is appended when neither the insertion nor the following text already supplies whitespace.
For multiple channels, Root and useMentionMulti<M>() accept a triggers map instead of a single channel. Each channel has items, getKey, getLabel, and optional getInsertText, allowSpaces, and filter. The multi-channel onSelect payload is keyed by the active trigger, for example { "@": person }.
Root also accepts children, unstyled, and handleRef. The handle exposes open(), close(), commit(item), and host. Opening rescans the existing text at the caret and retries a failed query; it does not insert a trigger or duplicate a pending or successful request.
MentionSelectMeta contains trigger, query, and triggerOffset. Offsets use UTF-16 within the adapter's current text region.
Compound components
| Component | Behavior |
|---|---|
Mention.Input | Native textarea. Accepts standard event handlers, controlled values, refs, styles, and form attributes. |
Mention.Popover | Listbox anchored to the caret by default, hidden after a failed search. Accepts div props and the positioning options below. |
Mention.List<T> | Calls its child function for each result. Optional trigger restricts the active channel. |
Mention.Item | Option with a value, children, and normal div props. |
Mention.Loading | Renders while a request is pending. |
Mention.Empty | Renders only after a successful query with no results. |
React context cannot infer a List's item type from Root. Supply Mention.List<Person> and ensure that its type matches the selected channel. The same responsibility applies to useMentionContext<Person>().
Popover positioning
| Prop | Behavior |
|---|---|
anchorRef | Optional RefObject<HTMLElement | null> for an element such as the composer wrapper. An omitted or empty ref keeps caret anchoring. |
placement | Preferred side and alignment: top, right, bottom, or left, optionally suffixed with -start or -end. Defaults to bottom-start; flips when space is constrained. |
matchAnchorWidth | Match the reference width, capped by available viewport space. Defaults to false. Use with an element anchor for a full-width composer panel. |
maxHeight | Maximum height in pixels, also limited by available space. Defaults to 280. |
container | Portal destination. Defaults to the editor document's body; null renders in place. This does not select the anchor. |
For a panel above the whole composer, attach a useRef<HTMLDivElement>(null) to its wrapper and pass it as anchorRef, with placement="top-start" and matchAnchorWidth. See the AI composer for the executable example. Mention retains collision handling and updates the position on relevant scrolling and resizing.
Hooks
useMention() and useMentionMulti() expose:
| Member | Purpose |
|---|---|
open, query, activeTrigger | Popup visibility, query, and visible channel. A failed search keeps its query but sets open to false and activeTrigger to null. |
items, status | Current results and idle / loading / success / error status. Old requests never supply current results. |
highlightedIndex | Active option index, or -1. |
getInputProps(props?) | Composes textarea props and registers the built-in adapter through its ref. Pass handlers into this method rather than overwriting its returned handlers. |
getEditorProps() | ARIA attributes for a host with its own event system. |
getPopoverProps() | Listbox attributes. |
getItemProps(item, index, props?) | Option attributes and composed pointer handlers. Supply React keys separately. |
setOpen(boolean) | Dismiss or rescan the current selection. Opening a failed search starts a new request for that query. |
commit(item) | Returns false if the item, text, or selection is no longer current. |
editor, setEditor(adapter) | Current host and registration. Clear on cleanup. |
refresh() | Rescan after an editor transaction or selection change. |
handleKeyDown(event) | Returns true when handled. Call before editor key bindings. |
useMentionContext<T>() returns this interface inside Root. For standalone hooks, render the popup with the returned props. A hook's popup styling and positioning are application-owned.
Values belong on the textarea's standard value and onChange props. There is no second value state on the mention hook.
Editor adapter
interface EditorSnapshot {
text: string;
caret: number;
key?: unknown;
}
interface MentionEdit {
from: number;
to: number;
text: string;
}
interface EditorAdapter<T> {
element: HTMLElement;
read(): EditorSnapshot | null;
getCaretRect(): DOMRect | null;
replace(edit: MentionEdit, item: T, meta: MentionSelectMeta): void | boolean;
}Return null when editing is unavailable, a selection spans a range, or composition is active. Keep offsets consistent within one editable region. Use key to distinguish regions with identical text. Replacements must use the host's transaction system; return false if the operation is rejected.
See the working editor integration.
Detection utility
findActiveMention(value, caret, trigger = "@", { allowSpaces: false }) returns { trigger, query } or null. The trigger can also be an array of characters. It scans backwards from the caret and suppresses mid-word triggers, with soft boundaries for selected Unicode scripts.
Pass { allowSpaces: true } to allow Unicode horizontal space separators (Zs) in the query. Tabs, line breaks, and U+FFFC editor atoms always stop the scan. See name matching for an opt-in local filter.