Components

MentionMenu

An anchored, grouped autocomplete popup for a caret-driven "@mention" trigger.

Available since@crisp-ui-kit/crisp@0.57.6

A floating, caret-anchored autocomplete popup — built for RichTextEditor's renderMentionPicker (crisp#372, #428), but generic: anchor is a bare {x, y} point, not a trigger element, so anything that already computes a caret position (a plain <input>/<textarea> via useMentionTrigger, a custom combobox) can drive one.

Ships two things together, since neither is useful alone: grouped-section rows (MentionMenuSection / MentionMenuItem, crisp#646 — a consumer still supplies its own "Users"/"Records" data, crisp only owns the group/row chrome and behaviour) and the floating, caret-anchored positioning + keyboard model (crisp#1009) that makes that list usable next to real text instead of centered like Command.

Installation

npm install @crisp-ui-kit/crisp

Props

MentionMenu

Prop

Type

MentionMenuSection

Prop

Type

MentionMenuItem

Prop

Type

Notes

  • Why not Command. Command composes a Zag dialog machine (modal, centered, focus-trapped) — its props have no anchor/position concept, and Zag's dialog machine has no notion of a virtual anchor point at all. MentionMenu instead shares Menu's approach (FloatingPortal + placeFloating), the one already built for a point-anchored popover.
  • Real DOM focus never moves. Unlike Menu's roving-focus buttons, MentionMenu never takes focus away from wherever the consumer's own field has it. ↑/↓/Enter/Escape are captured at document, ahead of the field's own keydown handling, and a virtual data-highlighted marker (mouse hover and keyboard agree on the one attribute) tracks the active row instead. A consumer that owns a real <input> and wants full aria-activedescendant wiring can pass a stable id — each row's DOM id is ${id}-option-${value}.
  • Grouping crosses section boundaries. ↑/↓ walk every MentionMenuItem in document order regardless of which MentionMenuSection it's in, the same way a flat list would.
  • Placement. Flips above the anchor when there isn't room below (the same threshold Menu uses). Horizontal viewport-edge clamping was intentionally left out pending a live measurement against Attio's own @mention popover — see the component's own doc comment.
  • A bare trigger shows nothing. Matching Attio: typing "@" with no query after it should render no picker at all — that's the consumer's own call inside renderMentionPicker (return null until query is non-empty), not something MentionMenu enforces itself.

On this page