Mention input
A text field whose @ references become inline entity chips. This is an app composition: the React implementation is apps/web/src/components/MentionInput.tsx (not in @acrm/ui), the styles are apps/web/src/ds/mention-input.css. It is a contenteditable surface styled like the Input box, single-line (.mi-editor) or multi-line (.mi-editor.mi-multiline), with a caret-anchored autocomplete menu fed by GET /mentions/search. Chips are <EntityRef variant="mini"> markup (span.eref-chip.eref-mini > .eref-chip-nm), the menu is the canonical .acrm-popover shell with .acrm-recordselect-opt rows. The catalog renders the emitted markup statically.
When to use
- Task text and note composer where the user refers to a person, company, deal, product or colleague by typing
@. - Chat-style composers (
onSubmit: Enter sends, Shift+Enter breaks the line). - Read-only rendering of the same text goes through
MentionText— same chips, no editing.
When not to use
- Plain text without references — Input or Textarea; the contenteditable surface costs more than it gives.
- Picking one record as a field value — Record select (the rail owner/tags pickers use
RailPickerMenu). - Free tags — Tag input; an @ chip is a reference, not a label.
- Rich formatting (headings, lists) — the note editor; Mention input keeps text plain plus chips.
Anatomy
- Editor
.mi-editor:min-height: 32px; padding: var(--sp-2) var(--sp-3),border: 1px solid var(--border-strong),border-radius: var(--radius-sm),background: var(--surface-100),font: var(--p),line-height: 1.5,width: 100%,white-space: pre-wrap,cursor: text;.mi-multilineraises it tomin-height: 88px. - Placeholder:
data-placeholdershown through:empty::beforein--fg-muted(contenteditable has none natively). - Focus:
border-color: var(--accent)+box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent). - Chip:
.eref-chip.eref-mini— inline,padding: 0 1px,--radius-xs; name.eref-chip-nm12px,--fg-secondary, dashed--border-strongunderline; hover--ink-900with--ink-500underline. Click opens the record;data-*carries type and id. Lost entity =.mi-lostplain text in--fg-secondary. - Menu
.mi-menu:position: fixed; z-index: 101,min-width: 280px,max-width: min(380px, 100vw - 16px),max-height: min(344px, 100vh - 16px)(~8 rows, scrolls),padding: var(--sp-2),--surface-100, 1px--border-strong,--radius-md,--shadow-pop; no scrim, closes on blur/Esc. Anchored to the caret line, flips above when out of room. - Row:
.acrm-recordselect-opt(32px,--radius-sm, hover--hover-surface) >.mi-opt-ic24px slot with an 18px icon inic-tone-{blue,purple,green,rose}per type (contact blue, organization purple, deal green, user/product rose) +.acrm-recordselect-tx(.nm500 13px/20px,.em300 12px--fg-secondary; the last.emis the type label and never truncates). - Empty state:
.acrm-recordselect-empty; a visually hidden.mi-srlive region announces the result count. - Props of note:
multiline,placeholder,ariaLabel,onChange(value with@[type:id|display]tokens),onMentionsChange,onSubmit,submitOnModEnter.
Best practices
Do
- Use it wherever the text may name a record; the token grammar (
@acrm/shared) is shared, so the same value renders everywhere. - Keep the field width like a text field (column width); the menu sizes itself to content.
- Show the chip as the record's display name only; the type is visible in the menu row, not in the chip.
- Choose
submitOnModEnterfor note composers (⌘/Ctrl+Enter sends) andonSubmitfor chat (Enter sends).
Don't
- Another mention or chip implementation — this is the only one; the component emits
.eref-chip(the old.mi-chip-*classes were dead CSS and were removed in acrm !4058, 28 Sep 2026). - An external rich-text library or a token visible to the user (
@[contact:…]must never leak into the UI). - A heading or eyebrow inside the menu; a group separator is the only allowed divider.
- Colouring the chip by type — mini EntityRef is neutral; the coloured glyph lives in the menu only.
Content
- Placeholder is a short prompt: "Add a note…", "Write a message…"; mention the
@only where users would not expect it ("Type @ to mention"). - Menu rows: name first, identifier (e-mail, domain) second, type label last ("Contact", "Company") — from
common:mention.type.*. - Empty state text is one line ("No results"); the minimum query length is
MENTION_MIN_QUERY. - A lost entity renders its last known display name in plain text — never "[deleted]" inside the chip.
Related
entity-ref(variant mini) — the chip.record-select— the row anatomy and the type B search panel.textarea— multi-line text without references.popover— the menu shell.- Stories:
components--mention-input--default,components--mention-input--sizes,components--mention-input--states,components--mention-input--composition.
Source: docs/text-field/mention-input.usage.md · GitLab