Context menu

Right-click inside the editor to open a custom menu instead of the browser's.

Installation

This pattern is built from files in @intentui/editor. Install the editor, then copy the code above into a component of your own.

npx shadcn@latest add @intentui/editor

What's included

PieceWhy it is here
RichTextExtensionLexical's rich text behavior. Every pattern needs it.
InitialStateExtensionApplies the seeded content immediately, so the server and the client render the same. Leave it out if your editor starts empty. See Seeding initial content.
LinkExtensionOnly for the "Remove link" item. Without it the editor has no links to remove, and the item never shows.
ContextMenuPluginListens for contextmenu on the editor and renders the menu. It takes no props.
ItemAction
Remove linkShown only when you right-click a link. Unlinks the text. An auto-detected link is marked as unlinked instead.
CutCuts the selection.
CopyCopies the selection.
PastePastes rich content from the clipboard.
Paste as plain textPastes the clipboard as plain text.
DeleteRemoves the selected image or divider, or otherwise the top-level block under the pointer.

Paste reads the clipboard with navigator.clipboard. If the browser denies access, the plugin calls window.alert("Clipboard access is not allowed"). Replace that call if you want a quieter failure.

Customize

The items are plain JSX in plugins/context-menu-plugin.tsx. Add, remove or reorder MenuItem elements to change the menu.

<MenuItem onAction={() => editor.dispatchCommand(COPY_COMMAND, null)}>
  <DocumentDuplicateIcon />
  Copy
</MenuItem>

To remove the pattern, delete ContextMenuPlugin. The browser's menu returns.

Styling

The menu is the Menu from @/components/ui/menu, opened by a MenuTrigger with trigger="contextMenu", and the plugin sets w-52. The Delete item uses intent="danger".