Mentions
Preview: Default
Textarea with mention suggestions (combobox pattern): type @ to open, arrows to move, Enter/Tab to insert, Escape to close. The textarea is a combobox (`aria-expanded`, `aria-activedescendant`); the text is controlled (`value`/`onChange`) or uncontrolled (`defaultValue`), and inserted mentions are reported through onMentionsChange.
Import
import { MentionsInput } from '@marbleui/ui'Props
<MentionsInput>
| Prop | Type | Default | Description |
|---|---|---|---|
| users *required | MentionUser[] | — | |
| className | string | — | |
| defaultValue | string | '' | |
| label | string | 'Comment' | |
| name | string | — | Form field name; the textarea submits its text. |
| onChange | (value: string) => void | — | |
| onMentionsChange | (ids: string[]) => void | — | |
| placeholder | string | 'Write a comment… use @ to mention' | |
| value | string | — |
Usage notes
Comment box that suggests people when you type @. For plain text use TextArea; to pick people from a list use ComboBox or TagsInput.
const team = [{ id: 'u1', name: 'Maya Chen', handle: 'maya' }, { id: 'u2', name: 'Charles Webb', handle: 'charles' }]
<MentionsInput label="Comment" users={team} onMentionsChange={setNotifyIds} />
@at the start or after a space lists up to six people matching name or handle. ↑/↓ move, Enter or Tab inserts@handle, Escape closes; the active option usesaria-activedescendantand the match count is announced.onMentionsChangereceives the ids mentioned in the text whenever that set changes, including when a mention is deleted by hand. Handles match whole words, so@adaisn’t found inside@adam.- The text is controlled (
value+onChange) or uncontrolled (defaultValue);namesubmits it with a form. - The textarea has
role="combobox"witharia-expanded, so screen readers know when the list is open. usersis a fixed list; there’s no async search.
Example source · show· hide
import { useState } from 'react'
import { MentionsInput } from './mentions'
const users = [{ id: '1', name: 'Maya Chen', handle: 'maya' }, { id: '2', name: 'Charles Webb', handle: 'charles' }, { id: '3', name: 'Ada Park', handle: 'ada' }, { id: '4', name: 'Grace Hopper', handle: 'grace' }, { id: '5', name: 'Leo Martins', handle: 'leo' }]
function Demo() {
const [ids, setIds] = useState<string[]>([])
return <div className="flex w-96 flex-col gap-2"><MentionsInput users={users} onMentionsChange={setIds} /><span className="text-xs text-fg-muted" aria-live="polite">Notifying: {ids.map((i) => users.find((u) => u.id === i)!.name).join(', ') || 'nobody'}</span></div>
}
export const styles = { Default: Demo }Source: packages/ui/src/mentions/mentions.tsx
Catalog
- Category
- editor
- Priority
- Extra
- Primitive
- composed
- React Aria
- Autocomplete
- Base UI
- Autocomplete