Skip to content

useFloatingToolbar Hook Error#4629

Merged
zbeyens merged 2 commits into
udecode:mainfrom
narraje:main
Sep 22, 2025
Merged

useFloatingToolbar Hook Error#4629
zbeyens merged 2 commits into
udecode:mainfrom
narraje:main

Conversation

@narraje
Copy link
Copy Markdown
Contributor

@narraje narraje commented Sep 19, 2025

Fix: Resolve infinite loop in useFloatingToolbar hook

Problem

The floating toolbar was causing infinite re-renders under certain conditions, leading to performance issues and potential browser hangs. This occurred when users interacted with text selections while the toolbar was visible.

Root Cause

The third useEffect in useFloatingToolbar had open in its dependency array while also calling setOpen inside the effect:

Before - Problematic code

React.useEffect(() => {
  if (
    !selectionExpanded ||
    !selectionText ||
    (mousedown && !open) ||  // ← Reads 'open'
    hideToolbar ||
    (readOnly && !showWhenReadOnly)
  ) {
    setOpen(false);  // ← Writes 'open'
  } else if (
    selectionText &&
    selectionExpanded &&
    (!waitForCollapsedSelection || readOnly)
  ) {
    setOpen(true);   // ← Writes 'open'
  }
}, [
  // ... other deps
  open,  // ← Creates feedback loop!
  // ...
]);

This created a feedback loop: setOpen → open changes → effect re-runs → setOpen → infinite loop.

Solution

Removed open from the dependency array - The effect logic doesn't actually depend on the current open value for decision-making.

Simplified the mousedown condition from (mousedown && !open) to just mousedown - The original condition was redundant since calling setOpen(false) when already closed is a no-op.

After - Fixed code
React.useEffect(() => {
  if (
    !selectionExpanded ||
    !selectionText ||
    mousedown ||  // ← Simplified condition
    hideToolbar ||
    (readOnly && !showWhenReadOnly)
  ) {
    setOpen(false);
  } else if (
    selectionText &&
    selectionExpanded &&
    (!waitForCollapsedSelection || readOnly)
  ) {
    setOpen(true);
  }
}, [  setOpen,
  editorId,
  focusedEditorId,
  hideToolbar,
  showWhenReadOnly,
  selectionExpanded,
  selectionText,
  mousedown,
  waitForCollapsedSelection,
  readOnly,
  // ← 'open' removed - no more infinite loop!
]);

Files Changed

packages/floating/src/hooks/useFloatingToolbar.ts

This fix maintains all existing functionality while eliminating the performance issue caused by the infinite loop.

@codesandbox
Copy link
Copy Markdown

codesandbox Bot commented Sep 19, 2025

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Sep 19, 2025

🦋 Changeset detected

Latest commit: 500dfd7

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

This PR includes changesets to release 2 packages
Name Type
@platejs/floating Patch
@platejs/link 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

@vercel
Copy link
Copy Markdown

vercel Bot commented Sep 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
plate Ready Ready Preview Comment Sep 19, 2025 8:14pm

@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. bug Something isn't working javascript Pull requests that update javascript code labels Sep 19, 2025
@zbeyens zbeyens merged commit 8ebaab1 into udecode:main Sep 22, 2025
6 checks passed
@claude claude Bot mentioned this pull request Sep 23, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working javascript Pull requests that update javascript code size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants