Headless suggestion menu for Tiptap editor

Headless components on top of Base UI: positioning, keyboard navigation, and the right ARIA patterns out of the box. You still choose the markup and styles — no fighting a theme you didn't pick.

npm i tiptap-suggestmenu Quick start GitHub

Live demos

One picker system, many product surfaces.

Demo

Type / to open the block picker — headings, lists, code blocks, dividers.

Code

Base UI-powered

Familiar primitives, editor-specific behavior.

Positioning comes from Base UI Popover primitives, while SuggestMenu layers on editor sessions, listbox behavior, and trigger lifecycle management.

Headless + composable

Bring your own markup, or mount the full compound component.

Use useSuggestMenu when you want total control, or pass props directly to <SuggestMenu>.

<SuggestMenu.Root editor={editor} triggerCharacter="@" items={items}>
  <SuggestMenu.Portal>
    <SuggestMenu.Positioner>...</SuggestMenu.Positioner>
  </SuggestMenu.Portal>
</SuggestMenu.Root>

Styling stays yours

Opaque enough for demos, open enough for production design systems.

Keep the surface transparent, use a plain white card, or layer in gradients and texture per column. The menu logic does not care how the container looks.

Core features

Triggers, grouping, async data, lifecycle, performance.

The docs go deeper into each part, but the homepage now keeps the entire story inside one connected grid.

Editing ergonomics

Placeholders & auto-close

Show ghost text when the query is empty, style it with data-suggest-placeholder, and dismiss the menu cleanly when no results remain.

You can also delete the typed query on dismiss, which makes slash menus and command pickers feel much more intentional.

Placeholder state is per trigger, so empty slash menus and empty mentions can behave differently.
Auto-close keeps the editor clean when filtering narrows the list down to nothing.

Accessible

Listbox semantics without moving focus out of the editor.

Keyboard navigation, screen reader support, and active-descendant focus management are built in, so you do not have to rebuild the hard parts.

Pills / inline nodes

Turn trigger text into chips, tokens, and editor-native inline nodes.

Register pill types in the extension and replace the trigger plus query with a structured node when the user selects an item.

Demo: different pills

Different triggers can resolve to completely different inline shapes.

Mention @, tag #, and variable $ items can each carry their own styling and insertion logic.

Performance

Large lists still feel responsive.

maxResults limits rendered items, and imperative highlight updates keep arrow-key navigation from re-rendering the whole list.

Collaboration-ready

Show menus only for the local user's edits.

Use shouldShow to suppress suggestion UI during remote changes, which makes Yjs-style collaborative editing much less noisy.

The fine print

Everything important, still inside the grid.

A few common questions before you jump into the docs or wire SuggestMenu into your own editor UI.

What is SuggestMenu?
A headless React component library that plugs into Tiptap's suggestion API. It gives you editor-aware menu state, keyboard handling, accessibility primitives, and compound components while leaving the UI design up to you.
Does it only work with Tiptap?
Yes. It is built on @tiptap/suggestion and expects a Tiptap editor instance.
Can I use my own search instead of Fuse.js?
Yes. Pass a custom filter function, or control the results externally with filteredItems and onQueryChange.
Does it work without a popup?
Yes. You can render the list inline instead of using a portal or popup and still keep the same session and interaction model.
Does it support collaborative editing?
Yes. Use shouldShow to hide menus for remote-originated changes, such as Yjs updates from another collaborator.
Is it accessible?
It uses listbox and option roles, aria-activedescendant, and full keyboard navigation while keeping focus in the editor. The Accessibility handbook page goes deeper.
Is it free?
Yes. MIT licensed.
Vue or Svelte support?
Not right now. The current package is React-only and built around Base UI's React primitives.