Skip to content

fix(react): fast typing no longer breaks suggestion menus - #3249

Merged
nperez0111 merged 2 commits into
TypeCellOS:mainfrom
safaweslati:fix/suggestion-menu-stable-reference
Oct 29, 2026
Merged

nperez0111 merged 2 commits into
TypeCellOS:mainfrom
safaweslati:fix/suggestion-menu-stable-reference

Conversation

@safaweslati

@safaweslati safaweslati commented Oct 23, 2026 •

Copy link
Copy Markdown

Summary

Fast typing while a suggestion menu trigger is active can crash a React app with error 185 ("Maximum update depth exceeded"). This PR keeps the reference that SuggestionMenuController and GridSuggestionMenuController give to GenericPopover stable while the menu does not move.

Rationale

Both controllers build reference with an inline useExtensionState selector. The selector returns a new object on every store update. Also, SuggestionMenuView writes referencePos with getBoundingClientRect().toJSON(), which is a new object on every update, also when the menu stays at the same place.

GenericPopover has an effect on props.reference that calls refs.setPositionReference(...). That is a state update in Floating UI. So each keystroke adds one more update that runs after the commit.

When keys arrive back to back, the browser handles the input before React gets to that update. Each sync commit then finishes with the update still waiting, and React counts it as a nested update. After about 50 keys, React throws error 185. It is not an infinite loop. It is a counter that the queued updates fill.

We see this in production. A user types / (or another trigger character) and then a sentence, quickly, on a slow machine. We reproduce it with Playwright and with Chrome DevTools CPU throttling at human speeds: 4x slower CPU at 100 ms per key, and 6x slower CPU at 150 ms per key.

Changes

  • SuggestionMenuController and GridSuggestionMenuController build reference with useMemo. The memo uses the editor element and the x, y, width and height values of referencePos, not the object identity.
  • getBoundingClientRect builds a DOMRect from those values, so it never returns a stale rectangle.
  • A new test, SuggestionMenuController.reference.test.tsx, opens each menu, types a query and checks that GenericPopover gets one reference for the whole query.

Impact

When the anchor moves (the query wraps to a new line, or the editor scrolls), the values change, so the popover gets a new reference and moves as before. When the anchor does not move, the popover no longer sets its position reference again on each keystroke.

Testing

  • The new test fails on main (5 references for 5 keys, in both controllers) and passes with the change (1 reference).
  • pnpm test in packages/react passes.
  • tsc --noEmit in packages/react passes. Lint and the formatter pass on the changed files. On Windows I could not run the type-aware lint step (tsgolint does not start), so CI is the first run of that step.
  • Manual: we applied the same change as a pnpm patch to @blocknote/react@0.55.0 in our app. In a production build, fast typing after / and [ gave no error in 7 of 7 runs. Before the change, the same input crashed in 2 of 3 runs. The two throttled human speeds above also gave no error.

Screenshots/Video

N/A. No visual change.

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Additional Notes

None.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • List and grid suggestion menus now retain stable positioning when their underlying element and bounds remain unchanged, even if callback or rectangle objects are recreated.
    • This avoids unnecessary changes to the menus’ positioning references while users type.
  • New Features
    • Store-based React hooks now support configurable equality comparisons, with shallow comparison remaining the default.

…t move

SuggestionMenuController and GridSuggestionMenuController built the
popover reference with an inline selector, so it was a new object on
every store update. GenericPopover then set its position reference
again on each keystroke. With fast typing, React counted these queued
updates as nested updates and threw error 185 after about 50 keys.

The reference now changes only with the editor element and the values
of referencePos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 23, 2026

Copy link
Copy Markdown

@safaweslati is attempting to deploy a commit to the TypeCell Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5c6d6a78-5bdb-4507-95bf-8392f320e5e3
Commits

Reviewing files that changed from the base of the PR and between ba9372f and 04e779c.

Files selected for processing: 4
  • packages/react/src/components/SuggestionMenu/GridSuggestionMenu/GridSuggestionMenuController.tsx
  • packages/react/src/components/SuggestionMenu/SuggestionMenuController.tsx
  • packages/react/src/hooks/useExtension.ts
  • packages/react/src/hooks/useStore.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

useStore and useExtensionState now support configurable equality functions. The list and grid suggestion-menu controllers compare references using the anchor element and its bounding-rectangle coordinates and dimensions. Tests check that menu references retain their identity across typing transactions.

Changes: Suggestion reference equality

Layer / File(s) Summary
Equality function API
packages/react/src/hooks/useStore.ts, packages/react/src/hooks/useExtension.ts
useStore accepts an optional equality function, defaulting to shallow, and passes it to the selector hook. useExtensionState accepts and forwards the function with its selector.
Suggestion-menu reference comparison
packages/react/src/components/SuggestionMenu/SuggestionMenuController.tsx, packages/react/src/components/SuggestionMenu/GridSuggestionMenu/GridSuggestionMenuController.tsx, packages/react/src/components/SuggestionMenu/SuggestionMenuController.reference.test.tsx
Both controllers compare menu references using the anchor element and its bounding-rectangle coordinates and dimensions. Tests check that list and grid menu references retain the same identity across typing transactions.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: nperez0111, matthewlipski, yousefed

Merge Risk: Minimal · up to 04e77

The change preserves existing defaults and stabilizes suggestion-menu references without an established merge-blocking regression.

Pre-merge checks: Passed 4
Check name Status Explanation
Description check Passed The description includes all required sections, explains the problem and rationale, lists the implementation changes, documents impact and testing, and records the unavailable type-aware lint step. Th…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title "fix(react): fast typing no longer breaks suggestion menus" matches the main change. The PR keeps the suggestion menu popover reference stable while the anchor does not move, which prevents …
Full details: Description check

Explanation

The description includes all required sections, explains the problem and rationale, lists the implementation changes, documents impact and testing, and records the unavailable type-aware lint step. The documentation checklist item remains unchecked, but this is non-critical for the fix.

Full details: Title check

Explanation

The title "fix(react): fast typing no longer breaks suggestion menus" matches the main change. The PR keeps the suggestion menu popover reference stable while the anchor does not move, which prevents repeated reference updates during fast typing (linked to React error 185). The title names the user-visible symptom and the affected area (react suggestion menus). It uses the conventional commit prefix and stays under 60 characters. It does not name the mechanism (reference memoization via equalityFn), but that detail is not required for a title.

Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the menu's place
While queries hop at a steady pace
The anchor stays, the bounds align
Each reference holds its line
Then carrots mark the test as fine

Comment @coderabbitai help to get the list of available commands.

@nperez0111
nperez0111 force-pushed the fix/suggestion-menu-stable-reference branch from 9354821 to 04e779c Compare October 29, 2026 14:36
@pkg-pr-new

pkg-pr-new Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@3249

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@3249

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@3249

@blocknote/diagram-block

npm i https://pkg.pr.new/@blocknote/diagram-block@3249

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@3249

@blocknote/math-block

npm i https://pkg.pr.new/@blocknote/math-block@3249

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@3249

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@3249

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@3249

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@3249

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@3249

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@3249

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@3249

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@3249

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@3249

@blocknote/xl-typst-exporter

npm i https://pkg.pr.new/@blocknote/xl-typst-exporter@3249

commit: 04e779c

@nperez0111 nperez0111 changed the title fix(react): keep the suggestion menu reference while the menu does not move fix(react): fast typing no longer breaks suggestion menus Oct 29, 2026
@nperez0111
nperez0111 merged commit 2005de4 into TypeCellOS:main Oct 29, 2026
30 of 32 checks passed
@nperez0111

Copy link
Copy Markdown
Contributor

Thanks @safaweslati for the fix

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.

2 participants