Skip to content

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.

On this page

Example

Loading example…
Mention Field.tsxtsx
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.

  1. MentionField

    Wrapper-free field provider that owns the message, active token, and caret position. Does not add a DOM element.

  2. Label

    Native label connected to the message input. Owns a DOM element.

  3. MentionFieldInput

    Native textarea that tracks the token and caret without moving DOM focus. Owns a DOM element.

  4. MentionFieldPopover

    Caret-anchored floating surface around the suggestion collection. Owns a DOM element.

  5. ListBox

    Explicit labelled collection of matching completions. Owns a DOM element.

  6. ListBoxItem

    One token completion. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start MentionField with a Label and MentionFieldInput.

  2. 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. 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

Importtsx
import { Label, ListBox, ListBoxItem, MentionField, MentionFieldInput, MentionFieldPopover } from "@comp0/react";

MentionField

Context only

Wrapper-free field provider that owns the message, active token, and caret position.

PropTypeDescription
valuestringControlled message text.
defaultValuestringInitial uncontrolled message text.
onChange(value: string) => voidReceives the next complete message.
triggersreadonly string[]Characters that begin a completion token; defaults to @.
filter(textValue: string, query: string) => booleanOptional client-side match rule for suggestion text.
asElementType | FragmentOptional provider root element.

Label

DOM element

Native label connected to the message input.

MentionFieldInput

DOM element

Native textarea that tracks the token and caret without moving DOM focus.

PropTypeDescription
namestringSubmission name for the complete message.
placeholderstringHint text; never a replacement for Label.

MentionFieldPopover

DOM element

Caret-anchored floating surface around the suggestion collection.

PropTypeDescription
offsetnumberGap from the caret in pixels; defaults to 4.

ListBox

DOM element

Explicit labelled collection of matching completions.

PropTypeDescription
aria-labelstringAccessible name for the suggestion collection.

ListBoxItem

DOM element

One token completion.

PropTypeDescription
valuestringText inserted after the active trigger.
textValuestringMatching 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 hookMeaning
[data-mention-field]Optional DOM root for the mention field.

MentionFieldInput

Style hookMeaning
[data-mention-active]The caret is inside a completion token.
[aria-activedescendant]The textarea points to the active suggestion while retaining focus.

MentionFieldPopover

Style hookMeaning
[data-open]Suggestions are visible.
[data-trigger]The active token trigger, such as @ or #.

ListBoxItem

Style hookMeaning
[data-active]The suggestion has the virtual keyboard highlight.

Keep exploring