Mention input
A textarea with @people and #channel mentions that act as single tokens, with suggestions at the caret.
inputsnew
Preview
Mention input preview
Live · keyboard ready
When to use
- Comment and reply boxes where people are tagged with @ and should be notified by id.
- Chat or task composers that link #channels or projects inline.
- Any text field whose stored value needs structured references alongside the plain text.
When not to use
- Use textarea for plain notes with no references.
- Use tag-input when the tokens are a separate list rather than part of a sentence.
- Use rich-text-editor when the text also needs headings, lists, or links.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "mention-input",
"type": "registry:ui",
"title": "Mention input",
"description": "A textarea with @people and #channel mentions that act as single tokens, with suggestions at the caret.",
"categories": [
"inputs"
],
"dependencies": [
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/mention-input/mention-input.tsx",
"type": "registry:component",
"target": "@components/manicat/mention-input/mention-input.tsx"
},
{
"path": "registry/components/mention-input/mention-input.module.css",
"type": "registry:component",
"target": "@components/manicat/mention-input/mention-input.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/mention-input",
"meta": {
"tier": "free",
"kind": "component",
"docs": "https://manicat.viraza.net/components/mention-input",
"markdown": "https://uiarc.dev/components/mention-input/markdown",
"tags": [
"inputs",
"new"
]
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { MentionInput } from "@/components/manicat/mention-input/mention-input";
export function MentionInputExample() {
return (
<MentionInput
aria-label="Note"
placeholder="Write a note, @ to mention someone"
people={[{ id: "ada", name: "Ada Lovelace", role: "Engineering" }]}
channels={[{ id: "general", name: "general", members: 12 }]}
/>
);
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Team note Mention people with @ and channels with # while writing a note.
Team note
Mention people with @ and channels with # while writing a note. preview
Live · keyboard ready
team-note-mention-people-with-and-channels-with-while-writing-a-note-.tsxtsx
"use client";
import { MentionInput } from "@/components/manicat/mention-input/mention-input";
export function MentionInputNoteExample() {
return (
<div className="w-full max-w-md">
<MentionInput
aria-label="Note"
placeholder="Write a note, @ to mention someone"
people={[
{ id: "ada", name: "Ada Lovelace", role: "Engineering" },
{ id: "grace", name: "Grace Mbeki", role: "Support" },
]}
channels={[{ id: "general", name: "general", members: 12 }]}
/>
</div>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| @ / # | Opens people or channel suggestions after a space, line start, or opening bracket or quote. |
| Arrow Down / Arrow Up | Moves through suggestions, wrapping at the ends. |
| Enter / Tab | Turns the highlighted suggestion into a mention. |
| Escape | Dismisses suggestions for the current trigger without leaving the field. |
| Backspace / Delete | Next to a mention, one press removes the whole token. |
| Arrow Left / Arrow Right | Steps over a mention as one unit. |
| Enter / Shift+Enter | With submitOnEnter, Enter submits and Shift+Enter adds a line. |
Accessibility
- The textarea is a combobox with aria-autocomplete="list", aria-expanded, aria-controls, and aria-activedescendant pointing at the highlighted option.
- Suggestions are a listbox labelled People or Channels, with options marked aria-selected.
- A polite live region announces the result count, such as 3 people or No matches.
- Mention tints come from an aria-hidden mirror behind a transparent textarea, so assistive tech reads the plain text.
- Choosing a suggestion types through execCommand insertText, so native undo keeps working.
Motion
- The field height springs to its content between minRows and maxRows.
- Suggestions pop in from the caret with a small scale and a snappy spring; the highlight glides between rows and the panel height springs as results change.
- Reduced motion jumps the height and highlight and fades the panel without scale or offset.
Responsive behavior
- Fills its container width. The suggestion panel is 272px wide, capped to the field width, and clamped so it never runs past the right edge.
- With placement auto the panel flips above the caret near the bottom of the viewport, which suits composers pinned to the bottom of a mobile screen.
- Options use pointer events and click, so touch taps choose a suggestion without a hover state.
Performance
- Each edit rebuilds a mirror of the text to draw token tints and reconciles mention offsets with a prefix and suffix diff; fine for messages, not for pages of text.
- Two ResizeObservers drive the field and panel height springs; ranking runs over the full people and channels arrays each keystroke, so pass a pre-filtered list past a few thousand entries.
Notes for AI
- Choose it for comment boxes, message composers, and task descriptions that tag people or channels. Use textarea for plain multi-line text and tag-input for a list of chips outside the text.
- Store serializeMentions(value) or the mentions array, not only value.text, so renamed people still resolve by id.
- Filter people on the server by passing a fresh people array per keystroke; ranking is prefix, then word start, then substring, then role or description.
- Hook a toolbar @ button to ref.openSuggestions("person").