Skip to content

fix(editor-input): support Lexical mention menu in Shadow DOM#459

Merged
jaieds merged 5 commits into
stagingfrom
fix/lexical-shadow-dom-mention
Jun 10, 2026
Merged

fix(editor-input): support Lexical mention menu in Shadow DOM#459
jaieds merged 5 commits into
stagingfrom
fix/lexical-shadow-dom-mention

Conversation

@jaieds

@jaieds jaieds commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes the Editor Input's mention/variable suggestions menu work when the editor is rendered inside a Shadow DOM.

The root cause is twofold: lexical 0.38 has no Shadow DOM selection support, and the mention plugin made several document-level assumptions that break across the shadow boundary.

Changes

  • Lexical Shadow DOM fix (PR facebook/lexical#7790) applied via patch-package over registry lexical@0.38.2. No vendored binaries — patches are committed text in patches/, applied on postinstall. CI-safe (installs from registry + applies the committed patch).
  • Local port of LexicalTypeaheadMenuPlugin to restore the menuRenderFn API removed in lexical 0.38 (keeps the custom EditorCombobox and the public menuComponent/menuItemComponent props).
  • Unique option keys (were all '') — fixes keyboard nav, highlighting, and the duplicate-key warning.
  • composedPath() outside-click detection + shadowRoot.activeElement blur so clicks inside the menu aren't misread across the shadow boundary.
  • preventDefault on item/menu mousedown so the editor keeps selection on click (otherwise the mention can't be inserted).
  • Portal the menu into the editor's shadow root so its styles apply.
  • scrollIntoView the highlighted option directly (the #typeahead-menu document lookup is null in Shadow DOM).
  • Dropdown width matches the editor (border-box, 100%).
  • InsideShadowDom story mounting via a real nested React root.
  • Removed unused component-data.json; added changelog entry.

Verified

npm ci (CI flow) installs registry 0.38.2 and applies all 6 patches ✔; Playwright in an open shadow root: typing, menu open, type-to-filter, mouse-click select, keyboard select + scroll-into-view, Escape/outside-click close. Non-shadow story unaffected. tsc + eslint clean; build passes.

Note

force-ui externalizes lexical, so the consuming app must carry the same patches/ + patch-package postinstall for the fix to reach its runtime — patch-package does not apply across the dependency boundary.

jaieds added 3 commits June 8, 2026 22:57
Apply the unmerged Lexical Shadow DOM fix (facebook/lexical#7790) via
patch-package over registry lexical@0.38.2, and fix the mention plugin's
Shadow-DOM-unsafe assumptions:

- Port LexicalTypeaheadMenuPlugin locally to restore the menuRenderFn API
  removed in lexical 0.38 (keeps the custom EditorCombobox + public
  menuComponent/menuItemComponent props).
- Give each mention option a unique key (was '' for all), fixing keyboard
  nav, highlighting and the duplicate-key warning.
- Use event.composedPath() for outside-click detection and shadowRoot
  .activeElement for blur, so clicks inside the menu aren't misread across
  the shadow boundary.
- preventDefault on item/menu mousedown so the editor keeps selection on
  click (otherwise the mention can't be inserted).
- Portal the menu into the editor's shadow root so its styles apply.
- scrollIntoView the highlighted option directly (the #typeahead-menu
  document lookup is null in Shadow DOM).
- Match dropdown width to the editor (border-box, 100%).
- Add InsideShadowDom story mounting via a real nested React root.
@socket-security

socket-security Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​lexical/​clipboard@​0.31.2 ⏵ 0.38.2100 +110071 +1100100
Updated@​lexical/​selection@​0.31.2 ⏵ 0.38.2100 +110072 +1100100
Updated@​lexical/​utils@​0.31.2 ⏵ 0.38.2100 +110073100100
Updated@​lexical/​table@​0.31.2 ⏵ 0.38.2100 +310087 +1100100
Updated@​lexical/​react@​0.31.2 ⏵ 0.38.29910098 +1100100

View full report

…typeahead anchor

Typing in consumers mounting many EditorInputs (e.g. SureRank metabox)
lagged badly (~300ms/keystroke, multi-second main-thread tasks). Two
compounding causes, both fixed here:

- Accordion: the accessibility rework kept collapsed Accordion.Content
  children mounted (aria-hidden), so consumers with heavy panel content
  (Lexical editors) mounted everything up front and re-rendered it all
  on every keystroke. Keep the ARIA region element in the DOM so the
  trigger's aria-controls/aria-labelledby still resolve, but unmount the
  children via AnimatePresence while collapsed, as before v1.7.11.

- EditorInput typeahead: the ported menu plugin created an anchor div on
  every render and appended it to document.body during render at every
  mount, forcing style recalcs per editor mount/unmount on heavy pages
  (and risking leaked divs from discarded renders). Create the anchor
  lazily and append it only when the menu actually opens.

Also memoize the mention trigger regexes per trigger and bail out of
setMenuParent when the shadow-root parent is unchanged, trimming the
per-keystroke render path.

Measured in the SureRank metabox repro: a fast-typed sentence went from
a 15.3s main-thread task (~333ms/keystroke) to 0.38s total, with
collapsed sections back to mounting zero editors.
@jaieds jaieds merged commit 3931f04 into staging Jun 10, 2026
6 of 7 checks passed
jaieds added a commit that referenced this pull request Jun 10, 2026
…ention

fix(editor-input): support Lexical mention menu in Shadow DOM
jaieds added a commit that referenced this pull request Jun 11, 2026
…ention

fix(editor-input): support Lexical mention menu in Shadow DOM
jaieds added a commit that referenced this pull request Jun 11, 2026
…ention

fix(editor-input): support Lexical mention menu in Shadow DOM
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