Skip to content

Fix BubbleMenu and FloatingMenu not supporting option updates after initialization#7445

Merged
bdbch merged 4 commits intodevelopfrom
claude/fix-tiptap-6963-AiiyN
Jan 24, 2026
Merged

Fix BubbleMenu and FloatingMenu not supporting option updates after initialization#7445
bdbch merged 4 commits intodevelopfrom
claude/fix-tiptap-6963-AiiyN

Conversation

@bdbch
Copy link
Member

@bdbch bdbch commented Jan 24, 2026

Changes Overview

Fixes the BubbleMenu and FloatingMenu components to properly update when props change after initial render. Previously, options like scrollTarget passed via useEffect were never applied because the plugins were only configured during construction.

Implementation Approach

Instead of re-registering the entire plugin when props change (which caused regressions in previous attempts), this PR:

  1. Adds updateOptions method to both BubbleMenuView and FloatingMenuView - Handles dynamic option updates including proper scroll listener management when scrollTarget changes
  2. Extends transaction handlers - Both support new updateOptions metadata type alongside existing updatePosition
  3. Refactors React components - Both now use ref-based props with a separate useEffect for dispatching option updates, avoiding full plugin re-registration

This approach keeps both menus consistent and avoids the performance issues that caused the previous fix to be reverted.

Testing Done

  • ESLint passes on all modified files
  • Verified the implementation follows existing patterns in the codebase
  • Logic reviewed to ensure scroll listeners are properly managed (removed before adding new ones)

Verification Steps

  1. Create a BubbleMenu or FloatingMenu with scrollTarget passed via useEffect:
const [scrollTarget, setScrollTarget] = useState(null);

useEffect(() => {
  setScrollTarget(document.querySelector('.scroll-container'));
}, []);

<BubbleMenu options={{ scrollTarget }} />
  1. Verify the scroll handler is properly attached after the ref is resolved
  2. Verify changing other props like shouldShow, updateDelay, etc. updates the plugin without re-registration

Additional Notes

Regarding non-memoized props: This implementation dispatches update transactions when props change (by reference). Unlike the previous reverted fix, this does NOT re-register the plugin - it only calls updateOptions. For optimal performance, users should memoize function/object props, but non-memoized props will not cause the severe regression seen before (no unregisterPlugin/registerPlugin cycle).

Bonus improvement for FloatingMenu: Previously, FloatingMenu re-registered the entire plugin on any prop change. This PR also fixes that behavior to match the new BubbleMenu pattern.

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.

Related Issues

Fixes #6963

The BubbleMenu component now properly updates when props change after the
initial render. Previously, options like scrollTarget were only applied
during plugin construction and never updated afterward.

Changes:
- Add updateOptions method to BubbleMenuView class that handles dynamic
  option updates including scrollTarget listener management
- Extend transaction handler to support 'updateOptions' metadata
- Add useEffect in React component to dispatch option updates when props
  change, avoiding full plugin re-registration

This allows users to dynamically pass configuration options retrieved via
useEffect (e.g., scrollTarget from a DOM ref) without needing workarounds
like conditional rendering.

https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
Apply the same fix from BubbleMenu to FloatingMenu for consistency.
Previously, FloatingMenu would re-register the entire plugin when props
changed. Now it uses the same updateOptions transaction pattern.

https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
Copilot AI review requested due to automatic review settings January 24, 2026 04:01
@changeset-bot
Copy link

changeset-bot bot commented Jan 24, 2026

🦋 Changeset detected

Latest commit: 91f38be

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

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

netlify bot commented Jan 24, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit 91f38be
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/697447cf271d06000825f9ec
😎 Deploy Preview https://deploy-preview-7445--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
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 ensures that React BubbleMenu and FloatingMenu components correctly react to prop changes after initialization, particularly for Floating UI options like scrollTarget, without repeatedly re-registering ProseMirror plugins.

Changes:

  • Refactors React BubbleMenu and FloatingMenu to register their plugins once per editor instance, tracking props via refs and dispatching updateOptions plugin metadata when React props change.
  • Adds updateOptions handling to BubbleMenuView and FloatingMenuView, including dynamic scroll listener management when options.scrollTarget changes.
  • Documents the behavior change in a new changeset, issuing patch bumps for @tiptap/extension-bubble-menu, @tiptap/extension-floating-menu, and @tiptap/react.

Reviewed changes

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

Show a summary per file
File Description
packages/react/src/menus/FloatingMenu.tsx Registers the floating menu plugin once per editor, tracks plugin options in a ref, and dispatches 'floatingMenu' / type: 'updateOptions' transactions when React props change.
packages/react/src/menus/BubbleMenu.tsx Mirrors the floating menu ref/effect pattern for the bubble menu, including getReferencedVirtualElement, and dispatches 'bubbleMenu' / type: 'updateOptions' transactions.
packages/extension-floating-menu/src/floating-menu-plugin.ts Extends FloatingMenuView to handle updateOptions meta, updating delays, appendTo, shouldShow, and options (including scroll listener migration on scrollTarget change).
packages/extension-bubble-menu/src/bubble-menu-plugin.ts Extends BubbleMenuView similarly with an updateOptions method and transaction handler, updating relevant fields and moving the scroll listener when options.scrollTarget changes.
.changeset/fix-bubble-menu-props-update.md Adds a changeset describing the fix so that the affected packages get patch releases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 24, 2026

Open in StackBlitz

@tiptap/extension-character-count

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

@tiptap/extension-dropcursor

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

@tiptap/extension-gapcursor

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

@tiptap/extension-focus

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

@tiptap/extension-history

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

@tiptap/extension-list-keymap

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

@tiptap/extension-list-item

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

@tiptap/extension-placeholder

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

@tiptap/extension-table-cell

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

@tiptap/extension-table-header

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

@tiptap/extension-table-row

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

@tiptap/extension-task-item

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

@tiptap/extension-task-list

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

@tiptap/core

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

@tiptap/extension-audio

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

@tiptap/extension-blockquote

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

@tiptap/extension-bold

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

@tiptap/extension-bubble-menu

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

@tiptap/extension-bullet-list

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

@tiptap/extension-code

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

@tiptap/extension-collaboration

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

@tiptap/extension-code-block-lowlight

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

@tiptap/extension-code-block

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

@tiptap/extension-color

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

@tiptap/extension-collaboration-caret

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

@tiptap/extension-details

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

@tiptap/extension-document

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

@tiptap/extension-drag-handle

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

@tiptap/extension-drag-handle-react

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

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

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

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

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

@tiptap/extension-file-handler

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

@tiptap/extension-emoji

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

@tiptap/extension-floating-menu

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

@tiptap/extension-font-family

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

@tiptap/extension-heading

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

@tiptap/extension-hard-break

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

@tiptap/extension-highlight

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

@tiptap/extension-horizontal-rule

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

@tiptap/extension-image

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

@tiptap/extension-invisible-characters

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

@tiptap/extension-italic

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

@tiptap/extension-link

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

@tiptap/extension-list

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

@tiptap/extension-mathematics

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

@tiptap/extension-mention

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

@tiptap/extension-ordered-list

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

@tiptap/extension-node-range

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

@tiptap/extension-paragraph

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

@tiptap/extension-subscript

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

@tiptap/extension-strike

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

@tiptap/extension-table-of-contents

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

@tiptap/extension-table

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

@tiptap/extension-superscript

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

@tiptap/extension-text

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

@tiptap/extension-text-align

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

@tiptap/extension-text-style

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

@tiptap/extension-typography

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

@tiptap/extension-twitch

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

@tiptap/extension-underline

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

@tiptap/extension-unique-id

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

@tiptap/extension-youtube

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

@tiptap/extensions

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

@tiptap/markdown

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

@tiptap/html

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

@tiptap/react

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

@tiptap/starter-kit

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

@tiptap/pm

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

@tiptap/static-renderer

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

@tiptap/suggestion

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

@tiptap/vue-2

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

@tiptap/vue-3

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

commit: 4f389ee

Address Copilot review feedback: the previous implementation only updated
scrollTarget when a new value was explicitly defined, preventing users from
resetting it back to the default window behavior.

Now when options.scrollTarget is undefined/null, it correctly defaults to
window, allowing proper reset of the scroll listener.

https://claude.ai/code/session_01RbvqtygmL8dKaCCSHPPUdS
Copy link
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

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


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bdbch bdbch merged commit 3e446fb into develop Jan 24, 2026
22 checks passed
@bdbch bdbch deleted the claude/fix-tiptap-6963-AiiyN branch January 24, 2026 04:27
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.

react BubbleMenu @tiptap/react/menus doesn't update on props change

2 participants