Fields
Mention Field
A multi-line field that completes a token beside the caret without replacing the surrounding message.
When to use it: Use it for people, topics, slash commands, or other token completions inside longer text.
Example
import {
Label,
ListBox,
ListBoxItem,
MentionField,
MentionFieldInput,
MentionFieldPopover,
} from "@comp0/react";
const teammates = [
{ name: "Aisha", role: "Design" },
{ name: "Diego", role: "Engineering" },
{ name: "Mina", role: "Research" },
{ name: "Ren", role: "Support" },
];
function startsWith(textValue: string, query: string) {
return textValue.toLocaleLowerCase().startsWith(query.toLocaleLowerCase());
}
export function Example() {
return (
<MentionField
as="div"
className="flex w-full max-w-sm flex-col gap-1.5"
defaultValue="Could @"
filter={startsWith}
>
<Label className="text-base font-medium text-zinc-900 sm:text-sm dark:text-zinc-100">
Message
</Label>
<MentionFieldInput
className="min-h-28 w-full rounded border border-zinc-950/10 bg-white px-3 py-2.5 text-base text-zinc-950 outline-teal-600 focus-visible:outline-2 sm:py-2 sm:text-sm dark:border-white/10 dark:bg-zinc-900 dark:text-zinc-50 dark:outline-teal-400"
name="message"
placeholder="Type @ to mention someone"
/>
<MentionFieldPopover className="w-56 rounded border-0 bg-white shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:shadow-none dark:ring-white/10">
<ListBox aria-label="Teammates" className="max-h-52 overflow-y-auto p-1 outline-none">
{teammates.map((teammate) => (
<ListBoxItem
key={teammate.name}
className="cursor-pointer rounded px-3 py-2 text-zinc-800 select-none data-active:bg-teal-100 data-active:text-teal-950 dark:text-zinc-100 dark:data-active:bg-teal-950 dark:data-active:text-teal-50"
textValue={teammate.name}
value={teammate.name}
>
<span className="block text-sm font-medium">@{teammate.name}</span>
<span className="block text-xs text-zinc-500 dark:text-zinc-400">
{teammate.role}
</span>
</ListBoxItem>
))}
</ListBox>
</MentionFieldPopover>
</MentionField>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
MentionField
Wrapper-free field provider that owns the message, active token, and caret position. Does not add a DOM element.
Label
Native label connected to the message input. Owns a DOM element.
MentionFieldInput
Native textarea that tracks the token and caret without moving DOM focus. Owns a DOM element.
MentionFieldPopover
Caret-anchored floating surface around the suggestion collection. Owns a DOM element.
ListBox
Explicit labelled collection of matching completions. Owns a DOM element.
ListBoxItem
One token completion. Owns a DOM element.
Step by step
- 1
Add the main part
Start MentionField with a Label and MentionFieldInput.
- 2
Add the supporting parts
Add MentionFieldPopover with an explicitly labelled ListBox and its ListBoxItem suggestions; the surface follows the active token at the caret.
- 3
Make the behavior clear
Pass triggers for token prefixes and filter for matching. Selection replaces only the active token and returns focus to the message.
Exampletsx <MentionField triggers={["@"]}> <Label>Message</Label> <MentionFieldInput name="message" /> <MentionFieldPopover> <ListBox aria-label="Teammates"> <ListBoxItem value="Aisha">@Aisha</ListBoxItem> </ListBox> </MentionFieldPopover> </MentionField>;
Keyboard
- ↓
- Moves virtual focus to the next suggestion.
- ↑
- Moves virtual focus to the previous suggestion.
- ↵
- Inserts the active suggestion at the caret.
- Esc
- Closes suggestions without changing the message.
- ←→
- Moves the native caret and updates the active token.
Forms and accessibility
MentionFieldInput submits the complete native textarea value under its name.
Accessibility checklist
- Give MentionFieldInput a visible Label and name the explicit ListBox when the field label does not describe its suggestions.
- Keep typed text valid without a selected suggestion; mention completion must remain optional.
- Render the virtually focused ListBoxItem while aria-activedescendant points to it.
- Do not trigger suggestions inside words such as email addresses.
API reference
import { Label, ListBox, ListBoxItem, MentionField, MentionFieldInput, MentionFieldPopover } from "@comp0/react";MentionField
Context onlyWrapper-free field provider that owns the message, active token, and caret position.
| Prop | Type | Description |
|---|---|---|
value | string | Controlled message text. |
defaultValue | string | Initial uncontrolled message text. |
onChange | (value: string) => void | Receives the next complete message. |
triggers | readonly string[] | Characters that begin a completion token; defaults to @. |
filter | (textValue: string, query: string) => boolean | Optional client-side match rule for suggestion text. |
as | ElementType | Fragment | Optional provider root element. |
Label
DOM elementNative label connected to the message input.
MentionFieldInput
DOM elementNative textarea that tracks the token and caret without moving DOM focus.
| Prop | Type | Description |
|---|---|---|
name | string | Submission name for the complete message. |
placeholder | string | Hint text; never a replacement for Label. |
MentionFieldPopover
DOM elementCaret-anchored floating surface around the suggestion collection.
| Prop | Type | Description |
|---|---|---|
offset | number | Gap from the caret in pixels; defaults to 4. |
ListBox
DOM elementExplicit labelled collection of matching completions.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Accessible name for the suggestion collection. |
ListBoxItem
DOM elementOne token completion.
| Prop | Type | Description |
|---|---|---|
value | string | Text inserted after the active trigger. |
textValue | string | Matching text when children contain rich content. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
MentionField
| Style hook | Meaning |
|---|---|
[data-mention-field] | Optional DOM root for the mention field. |
MentionFieldInput
| Style hook | Meaning |
|---|---|
[data-mention-active] | The caret is inside a completion token. |
[aria-activedescendant] | The textarea points to the active suggestion while retaining focus. |
MentionFieldPopover
| Style hook | Meaning |
|---|---|
[data-open] | Suggestions are visible. |
[data-trigger] | The active token trigger, such as @ or #. |
ListBoxItem
| Style hook | Meaning |
|---|---|
[data-active] | The suggestion has the virtual keyboard highlight. |