Mention
Inline @-mention primitive: a combobox that tracks the caret inside a textarea, filters options as you type, and inserts the chosen token. The trigger character, options, and filtering are all configurable.
Features
@) and custom filter predicate.Example
Anatomy
import { Mention } from '@wire-ui/react'
const people = [
{ id: 1, label: 'Ada Lovelace' },
{ id: 2, label: 'Alan Turing' },
{ id: 3, label: 'Grace Hopper' },
]
<Mention.Root options={people} className="relative">
<Mention.Input placeholder="Type @ to mention someone…" />
<Mention.Content>
<Mention.Items>
{({ option }) => <div>{option.label}</div>}
</Mention.Items>
<Mention.Empty>No people found</Mention.Empty>
</Mention.Content>
</Mention.Root>Styling
Mention.Root must be positioned (relative) so the Content listbox can anchor to the caret — it is absolutely positioned at the computed coordinates. Each option exposes data-active (the highlighted item) and data-disabled, so you can style hover/active and disabled states with attribute selectors.
<div className="
data-[active]:bg-black data-[active]:text-white
data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed
">
{option.label}
</div>Using data attributes
Mention.Content sets data-state="open" (it only renders while open). Each rendered option sets data-active when highlighted and data-disabled when the option is disabled. Mention.Root sets data-disabled when the whole control is disabled.
/* Highlighted option */
[data-active] { background: #000; color: #fff; }
/* Disabled option */
[data-disabled] { opacity: 0.4; cursor: not-allowed; }Root props
| Prop | Type | Default | Description |
|---|---|---|---|
options | MentionOption[] | required | Options shown when the trigger is active |
value | string | — | Controlled text value |
defaultValue | string | '' | Initial text value (uncontrolled) |
onChange | (value: string) => void | — | Called whenever the text changes |
trigger | string | '@' | Character that opens the menu |
filter | (option: MentionOption, query: string) => boolean | label includes query | Predicate used to filter options against the current query |
onSelect | (option: MentionOption) => void | — | Called when an option is chosen |
appendSpace | boolean | true | Append a space after the inserted mention |
disabled | boolean | false | Disable the whole control |
Input props
Accepts all native <textarea> attributes (e.g. rows, placeholder, aria-label). The value and disabled are managed by Mention.Root.
Items props
| Prop | Type | Description |
|---|---|---|
children | (props: MentionItemRenderProps) => ReactNode | Render function called for each filtered option |
MentionItemRenderProps is { option: MentionOption; active: boolean; index: number }.
Content / Empty props
Both accept all native <div> attributes. Content renders only while the menu is open; Empty renders only while the menu is open and no options match.
MentionOption
| Field | Type | Description |
|---|---|---|
id | string | number | Unique key |
label | string | Display text — also inserted after the trigger by default |
value | string | Optional value inserted instead of label |
disabled | boolean | Skip during keyboard navigation and ignore on click |
Data attributes
| Attribute | Element | Values |
|---|---|---|
data-state | Content | "open" |
data-active | Option | Present on the highlighted option |
data-disabled | Root, Option | Present when disabled |
Input also sets aria-autocomplete="list", aria-expanded, aria-controls, and aria-activedescendant. Content sets role="listbox"; each option sets role="option" and aria-selected.
Accessibility
- Implements the WAI-ARIA combobox/listbox pattern. The textarea owns the listbox via
aria-controlsand tracks the highlighted option viaaria-activedescendant. - The trigger only opens at the start of the text or after whitespace, so addresses like
a@b.comdo not trigger the menu. - Disabled options are skipped during arrow-key navigation and cannot be selected.
Keyboard Interactions
| Key | Description |
|---|---|
| ArrowDown | Move to the next option (skips disabled). |
| ArrowUp | Move to the previous option (skips disabled). |
| Enter / Tab | Selects the highlighted option. |
| Escape | Dismisses the menu for the current token. |