Composition
SuggestMenu can be used in two ways: a simple API (props on <SuggestMenu>) or a composable API (useSuggestMenu + menu prop). Layout can be floating (Portal + Positioner + Popup) or inline (list as direct children).
Simple vs composable API
Simple: Pass editor, triggerCharacter, items, and other options directly to <SuggestMenu>. The component manages state internally. Best when the menu is the only thing that needs to react to the session.
Composable: Call useSuggestMenu(editor, options) and pass the returned instance directly to <SuggestMenu menu={instance}>. Use this when you need menu state outside the tree (e.g. parent wrappers, animations, conditional layout).
Floating vs inline layout
Floating: Use SuggestMenu.Portal + Positioner + Popup so the list is portaled and positioned near the cursor. This is the typical “dropdown” pattern.
Inline: Omit Portal/Positioner/Popup and render SuggestMenu.List (and children) as direct children of SuggestMenu. The list appears in the DOM where you put it (e.g. below the input in a chat UI). Same API for items and keyboard; only the layout differs.
Patterns
- Standard floating popup — one
SuggestMenuwith Portal → Positioner → Popup → List. - Chat input with inline expanding panel (Granola-style) — no Portal; list in a panel that expands below the input.
- Notion-style editor — multiple
SuggestMenuroots (e.g. @, /, #) in one editor; only one session active at a time. - Custom panel driven by
useSuggestMenu— use the hook, render your own wrapper and list with the instance.