Suggestion

A menu of commands that opens above a chat input, like the list a slash brings up.

Usage

When to reach for Suggestion, how to wire it to your input, and the decisions it leaves to you.

When to use

Suggestion is a menu of commands or references that opens from a chat input when the reader types a trigger character. It keeps the reader typing: they pick an item with the keyboard and carry on.
  • Slash commands in a prompt box: /summarize, /translate.
  • Mentions and references: @ for a person or a file, # for a document or a topic.
  • A short list that narrows as the reader types after the trigger.
Use something else when
  • The suggestions are full prompts the reader starts a conversation with. That is Prompts, which shows them as cards the reader can see before typing anything.
  • The input is an ordinary form field with a list of completions. That is AutoComplete, or Mentions for @ mentions inside a plain text area.
  • The reader picks a value from a fixed set and types nothing. That is Select or Cascader.

You decide when it opens

The menu never opens on its own. Your input's onChange watches the text and calls onTrigger when the trigger character appears.
  • Close it yourself when the trigger goes. If the reader deletes the /, the menu stays open until you call onTrigger(false). Picking an item, Escape and a click outside close it for you.
  • Open it on the trigger at the start of the text, or after a space. A / inside a URL or a date should not open a command menu.
  • onSelect hands you the item's value, and writing it into the input is your job. Replace the trigger and what was typed after it, and leave a trailing space so the reader can keep typing.

Pass onKeyDown to your input

Without onKeyDown, the menu is mouse only. Focus stays in your input while the menu is open, so the keys only reach the menu through the onKeyDown that children receives. Pass it to the input's own onKeyDown.
  • With it, the arrow keys move through the items, Enter picks one and Escape closes the menu.
  • With Sender, it also stops Enter from sending the message while the menu is open. Without it, the reader who presses Enter to pick a command sends a half-typed prompt instead.
  • If your input already has an onKeyDown, call Suggestion's first and return what it returns. That return value is what keeps Enter from sending.

Items, and filtering them

Keep the list short enough to scan. The menu scrolls after about eight rows, and a reader in the middle of a sentence will not scroll.
  • Give each item a value that is unique within its column. The keyboard tracks the active row by value, so two items with the same value confuse it.
  • A function in items is also called with nothing. It runs once before any trigger, with no argument. Give its parameter a default, like (query = "") => ..., so a call like query.toLowerCase() does not throw on the first render.
  • Pass the text after the trigger to onTrigger(query) on every change, and filter in items. When nothing matches, close the menu with onTrigger(false) rather than showing an empty one.
  • An item with children opens a second column and cannot be picked itself. Use one level for most commands, and a second only when the first is a real category.
  • icon and extra help scanning. Use extra for a short hint or a shortcut, not a sentence.

Where the menu goes

The menu opens above the input, which suits a chat input at the bottom of the page.
  • block makes the menu as wide as the input. Use it when the items carry an extra, so the hints line up at the far edge.
  • Inside a scrolling panel or a drawer, pass getPopupContainer the scrolling element, so the menu moves with the input instead of staying where it opened.

Restyling it

Use the semantic keys: root, content for the box around your input and popup for the menu. The menu is rendered outside the component, so a class on the root does not reach it, and popup does.