Skip to content

feat: Added showOnMouseUp option to bubble menu#7500

Closed
Aslam97 wants to merge 3 commits intodevelopfrom
feat/bubble-menu-patch
Closed

feat: Added showOnMouseUp option to bubble menu#7500
Aslam97 wants to merge 3 commits intodevelopfrom
feat/bubble-menu-patch

Conversation

@Aslam97
Copy link
Copy Markdown
Member

@Aslam97 Aslam97 commented Feb 4, 2026

Changes Overview

Adds a new showOnMouseUp option to the bubble menu that defers showing the menu until the mouse button is released, similar to Notion's text selection behavior.

Implementation Approach

Added a new optional showOnMouseUp prop (default: false) to the bubble menu that defers menu display until mouseup occurs.

Key implementation details:

  • Track mouse state via isMouseDown flag
  • Store pending updates while mouse is down instead of immediately showing the menu
  • Process pending updates on mouseup to display the menu

Testing Done

  • Verified menu appears only after mouseup when showOnMouseUp: true

Verification Steps

  1. Enable the showOnMouseUp: <BubbleMenu showOnMouseUp={true} />
  2. Click and drag to select text - menu should NOT appear during selection
  3. Release mouse button - menu should appear at selection

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Copilot AI review requested due to automatic review settings February 4, 2026 13:06
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 4, 2026

🦋 Changeset detected

Latest commit: cada11f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 72 packages
Name Type
@tiptap/extension-bubble-menu Major
@tiptap/react Major
@tiptap/vue-2 Major
@tiptap/vue-3 Major
@tiptap/extension-drag-handle-react Major
@tiptap/extension-drag-handle-vue-2 Major
@tiptap/extension-drag-handle-vue-3 Major
@tiptap/core Major
@tiptap/extension-audio Major
@tiptap/extension-blockquote Major
@tiptap/extension-bold Major
@tiptap/extension-bullet-list Major
@tiptap/extension-code-block-lowlight Major
@tiptap/extension-code-block Major
@tiptap/extension-code Major
@tiptap/extension-collaboration-caret Major
@tiptap/extension-collaboration Major
@tiptap/extension-color Major
@tiptap/extension-details Major
@tiptap/extension-document Major
@tiptap/extension-drag-handle Major
@tiptap/extension-emoji Major
@tiptap/extension-file-handler Major
@tiptap/extension-floating-menu Major
@tiptap/extension-font-family Major
@tiptap/extension-hard-break Major
@tiptap/extension-heading Major
@tiptap/extension-highlight Major
@tiptap/extension-horizontal-rule Major
@tiptap/extension-image Major
@tiptap/extension-invisible-characters Major
@tiptap/extension-italic Major
@tiptap/extension-link Major
@tiptap/extension-list Major
@tiptap/extension-mathematics Major
@tiptap/extension-mention Major
@tiptap/extension-node-range Major
@tiptap/extension-ordered-list Major
@tiptap/extension-paragraph Major
@tiptap/extension-strike Major
@tiptap/extension-subscript Major
@tiptap/extension-superscript Major
@tiptap/extension-table-of-contents Major
@tiptap/extension-table Major
@tiptap/extension-text-align Major
@tiptap/extension-text-style Major
@tiptap/extension-text Major
@tiptap/extension-twitch Major
@tiptap/extension-typography Major
@tiptap/extension-underline Major
@tiptap/extension-unique-id Major
@tiptap/extension-youtube Major
@tiptap/extensions Major
@tiptap/html Major
@tiptap/markdown Major
@tiptap/pm Major
@tiptap/starter-kit Major
@tiptap/static-renderer Major
@tiptap/suggestion Major
@tiptap/extension-character-count Major
@tiptap/extension-dropcursor Major
@tiptap/extension-focus Major
@tiptap/extension-gapcursor Major
@tiptap/extension-history Major
@tiptap/extension-list-item Major
@tiptap/extension-list-keymap Major
@tiptap/extension-placeholder Major
@tiptap/extension-table-cell Major
@tiptap/extension-table-header Major
@tiptap/extension-table-row Major
@tiptap/extension-task-item Major
@tiptap/extension-task-list Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 4, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit cada11f
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/69845b2a67727300081f2e54
😎 Deploy Preview https://deploy-preview-7500--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new showOnMouseUp option to the BubbleMenu component that defers the menu display until the mouse button is released after text selection, similar to Notion's behavior. This prevents the menu from appearing and following the cursor during text selection.

Changes:

  • Added showOnMouseUp boolean option (default: false) to BubbleMenuPluginProps interface with comprehensive JSDoc documentation
  • Implemented mouse state tracking via event handlers in BubbleMenuView class to defer menu display while mouse is down
  • Integrated the new option across all framework bindings (React, Vue 2, Vue 3) and the extension configuration

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/extension-bubble-menu/src/bubble-menu-plugin.ts Core implementation: adds showOnMouseUp property, mouse event handlers, pending update logic, and cleanup
packages/extension-bubble-menu/src/bubble-menu.ts Adds showOnMouseUp to extension default options
packages/react/src/menus/BubbleMenu.tsx Adds showOnMouseUp prop with default value false to React BubbleMenu component
packages/vue-3/src/menus/BubbleMenu.ts Adds showOnMouseUp prop with default value false to Vue 3 BubbleMenu component
packages/vue-2/src/menus/BubbleMenu.ts Adds showOnMouseUp prop with default value false and to interface for Vue 2 BubbleMenu component

Comment thread packages/extension-bubble-menu/src/bubble-menu-plugin.ts
Comment thread packages/extension-bubble-menu/src/bubble-menu-plugin.ts
Comment thread packages/extension-bubble-menu/src/bubble-menu.ts
Comment thread packages/react/src/menus/BubbleMenu.tsx
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 4, 2026

Open in StackBlitz

@tiptap/extension-character-count

npm i https://pkg.pr.new/@tiptap/extension-character-count@7500

@tiptap/extension-dropcursor

npm i https://pkg.pr.new/@tiptap/extension-dropcursor@7500

@tiptap/extension-focus

npm i https://pkg.pr.new/@tiptap/extension-focus@7500

@tiptap/extension-gapcursor

npm i https://pkg.pr.new/@tiptap/extension-gapcursor@7500

@tiptap/extension-history

npm i https://pkg.pr.new/@tiptap/extension-history@7500

@tiptap/extension-list-item

npm i https://pkg.pr.new/@tiptap/extension-list-item@7500

@tiptap/extension-list-keymap

npm i https://pkg.pr.new/@tiptap/extension-list-keymap@7500

@tiptap/extension-placeholder

npm i https://pkg.pr.new/@tiptap/extension-placeholder@7500

@tiptap/extension-table-header

npm i https://pkg.pr.new/@tiptap/extension-table-header@7500

@tiptap/extension-table-cell

npm i https://pkg.pr.new/@tiptap/extension-table-cell@7500

@tiptap/extension-table-row

npm i https://pkg.pr.new/@tiptap/extension-table-row@7500

@tiptap/extension-task-item

npm i https://pkg.pr.new/@tiptap/extension-task-item@7500

@tiptap/extension-task-list

npm i https://pkg.pr.new/@tiptap/extension-task-list@7500

@tiptap/core

npm i https://pkg.pr.new/@tiptap/core@7500

@tiptap/extension-audio

npm i https://pkg.pr.new/@tiptap/extension-audio@7500

@tiptap/extension-blockquote

npm i https://pkg.pr.new/@tiptap/extension-blockquote@7500

@tiptap/extension-bubble-menu

npm i https://pkg.pr.new/@tiptap/extension-bubble-menu@7500

@tiptap/extension-bold

npm i https://pkg.pr.new/@tiptap/extension-bold@7500

@tiptap/extension-code

npm i https://pkg.pr.new/@tiptap/extension-code@7500

@tiptap/extension-code-block

npm i https://pkg.pr.new/@tiptap/extension-code-block@7500

@tiptap/extension-bullet-list

npm i https://pkg.pr.new/@tiptap/extension-bullet-list@7500

@tiptap/extension-collaboration

npm i https://pkg.pr.new/@tiptap/extension-collaboration@7500

@tiptap/extension-code-block-lowlight

npm i https://pkg.pr.new/@tiptap/extension-code-block-lowlight@7500

@tiptap/extension-collaboration-caret

npm i https://pkg.pr.new/@tiptap/extension-collaboration-caret@7500

@tiptap/extension-color

npm i https://pkg.pr.new/@tiptap/extension-color@7500

@tiptap/extension-details

npm i https://pkg.pr.new/@tiptap/extension-details@7500

@tiptap/extension-document

npm i https://pkg.pr.new/@tiptap/extension-document@7500

@tiptap/extension-drag-handle

npm i https://pkg.pr.new/@tiptap/extension-drag-handle@7500

@tiptap/extension-drag-handle-react

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-react@7500

@tiptap/extension-drag-handle-vue-2

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-2@7500

@tiptap/extension-emoji

npm i https://pkg.pr.new/@tiptap/extension-emoji@7500

@tiptap/extension-drag-handle-vue-3

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-3@7500

@tiptap/extension-file-handler

npm i https://pkg.pr.new/@tiptap/extension-file-handler@7500

@tiptap/extension-floating-menu

npm i https://pkg.pr.new/@tiptap/extension-floating-menu@7500

@tiptap/extension-font-family

npm i https://pkg.pr.new/@tiptap/extension-font-family@7500

@tiptap/extension-hard-break

npm i https://pkg.pr.new/@tiptap/extension-hard-break@7500

@tiptap/extension-heading

npm i https://pkg.pr.new/@tiptap/extension-heading@7500

@tiptap/extension-highlight

npm i https://pkg.pr.new/@tiptap/extension-highlight@7500

@tiptap/extension-image

npm i https://pkg.pr.new/@tiptap/extension-image@7500

@tiptap/extension-horizontal-rule

npm i https://pkg.pr.new/@tiptap/extension-horizontal-rule@7500

@tiptap/extension-invisible-characters

npm i https://pkg.pr.new/@tiptap/extension-invisible-characters@7500

@tiptap/extension-italic

npm i https://pkg.pr.new/@tiptap/extension-italic@7500

@tiptap/extension-link

npm i https://pkg.pr.new/@tiptap/extension-link@7500

@tiptap/extension-list

npm i https://pkg.pr.new/@tiptap/extension-list@7500

@tiptap/extension-mathematics

npm i https://pkg.pr.new/@tiptap/extension-mathematics@7500

@tiptap/extension-node-range

npm i https://pkg.pr.new/@tiptap/extension-node-range@7500

@tiptap/extension-mention

npm i https://pkg.pr.new/@tiptap/extension-mention@7500

@tiptap/extension-ordered-list

npm i https://pkg.pr.new/@tiptap/extension-ordered-list@7500

@tiptap/extension-paragraph

npm i https://pkg.pr.new/@tiptap/extension-paragraph@7500

@tiptap/extension-strike

npm i https://pkg.pr.new/@tiptap/extension-strike@7500

@tiptap/extension-subscript

npm i https://pkg.pr.new/@tiptap/extension-subscript@7500

@tiptap/extension-superscript

npm i https://pkg.pr.new/@tiptap/extension-superscript@7500

@tiptap/extension-table

npm i https://pkg.pr.new/@tiptap/extension-table@7500

@tiptap/extension-table-of-contents

npm i https://pkg.pr.new/@tiptap/extension-table-of-contents@7500

@tiptap/extension-text

npm i https://pkg.pr.new/@tiptap/extension-text@7500

@tiptap/extension-text-style

npm i https://pkg.pr.new/@tiptap/extension-text-style@7500

@tiptap/extension-text-align

npm i https://pkg.pr.new/@tiptap/extension-text-align@7500

@tiptap/extension-twitch

npm i https://pkg.pr.new/@tiptap/extension-twitch@7500

@tiptap/extension-typography

npm i https://pkg.pr.new/@tiptap/extension-typography@7500

@tiptap/extension-underline

npm i https://pkg.pr.new/@tiptap/extension-underline@7500

@tiptap/extension-unique-id

npm i https://pkg.pr.new/@tiptap/extension-unique-id@7500

@tiptap/extension-youtube

npm i https://pkg.pr.new/@tiptap/extension-youtube@7500

@tiptap/extensions

npm i https://pkg.pr.new/@tiptap/extensions@7500

@tiptap/markdown

npm i https://pkg.pr.new/@tiptap/markdown@7500

@tiptap/pm

npm i https://pkg.pr.new/@tiptap/pm@7500

@tiptap/starter-kit

npm i https://pkg.pr.new/@tiptap/starter-kit@7500

@tiptap/react

npm i https://pkg.pr.new/@tiptap/react@7500

@tiptap/suggestion

npm i https://pkg.pr.new/@tiptap/suggestion@7500

@tiptap/vue-2

npm i https://pkg.pr.new/@tiptap/vue-2@7500

@tiptap/static-renderer

npm i https://pkg.pr.new/@tiptap/static-renderer@7500

@tiptap/vue-3

npm i https://pkg.pr.new/@tiptap/vue-3@7500

@tiptap/html

npm i https://pkg.pr.new/@tiptap/html@7500

commit: cada11f

Copy link
Copy Markdown
Member

@bdbch bdbch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I should approve or reject. Quick question:

  • This is meant that while I select something, the Menu only opens after the selection is finished and my mouse is let go right? Should this also work with keyboard selections? In that case - maybe it's better to not handle mouse/keyboard events but build this logic around transactions that update the selection?
  • Is this in conflict with shouldShow

overall the code looks good to me, just want to make sure we build this the right way as I don't know where exactly the requirement came from.

'@tiptap/extension-bubble-menu': minor
---

Added `showOnMouseUp` option to bubble menu. This option allows the bubble menu to be displayed when the user releases the mouse button after a text selection, enhancing the user experience during text editing.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this conflicting with the Bubble Menu's shouldShow option? How do they work together?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn’t conflict with shouldShow. The menu is shown only after the user releases the mouse (mouseup), and then it goes through shouldShow for validation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not handle keyboard selection, it only apply to mouse selection

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"maybe it's better to not handle mouse/keyboard events but build this logic around transactions that update the selection?" I am not sure about this one, since what user want is they dont want to see the floating before releasing the mouse (similiar to Notion)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that would work - what we would need to do is onTransaction, check if the transaction changes the selection object - and if it does, we'd need to start a timeout / debounce that only resolves when no other transaction in X time occured again - and just then we "activate" the bubble menu so it can be shown. That would mean that it would work for all kind of interactions that change the selection.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. The current showOnMouseUp works by deferring updates while the mouse is down, I can refactor it so the menu only shows on a commit selection transaction instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry Aslam, coming back to this. I'm not sure if I'd want this functionality on top of shouldShow. Don't you think this behavior is more an integration topic and should be handled by the dev implementing it?

shouldShow should be able to handle this just fine if the user tracks the mousedown state somewhere & checks for it in shouldShow.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have send them how they can achieve the same behaviour without adding this implementation to the core package. closing this PR

@Aslam97 Aslam97 closed this Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants