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.
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.
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/suggestionand expects a Tiptap editor instance. - Can I use my own search instead of Fuse.js?
- Yes. Pass a custom
filterfunction, or control the results externally withfilteredItemsandonQueryChange. - 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
shouldShowto 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.