Skip to content

[lexical-react] Revert revert: Remove deprecated ContextMenu, consolidate menu rendering with backward-compatible menuRenderFn#8199

Merged
thatmichael85 merged 3 commits intomainfrom
users/thatmichael85/revert-7997-menu-consolidation
Mar 9, 2026
Merged

[lexical-react] Revert revert: Remove deprecated ContextMenu, consolidate menu rendering with backward-compatible menuRenderFn#8199
thatmichael85 merged 3 commits intomainfrom
users/thatmichael85/revert-7997-menu-consolidation

Conversation

@thatmichael85
Copy link
Contributor

@thatmichael85 thatmichael85 commented Mar 9, 2026

Summary

Breaking Changes

  • LexicalContextMenuPlugin is removed. Use LexicalNodeContextMenuPlugin instead (available since v0.32.0). See the playground ContextMenuPlugin for a migration example.
  • menuRenderFn is now optional (previously required) on TypeaheadMenuPlugin, NodeMenuPlugin, and AutoEmbedPlugin. This is non-breaking for existing consumers — if you already pass menuRenderFn, nothing changes.

Backward Compatibility

This PR was designed to be backward-compatible with existing consumers, including Meta's internal www codebase:

  • All consumers that currently pass menuRenderFn will continue to work unchanged — the prop is now optional, not removed.
  • MenuRenderFn type remains exported from all entry points.
  • PUNCTUATION constant is preserved.
  • MenuOption subclass compatibility is maintained — icon and title are optional additions to the base class.
  • Flow types match the TypeScript source for type-safe consumption.
  • Verified zero internal consumers of the deleted LexicalContextMenuPlugin.
  • All internal typeahead consumers (emoji picker, component picker, mentions, etc.) pass menuRenderFn and are unaffected by this change.

Test Plan

  • 28 new unit tests covering:
    • MenuOption class (key, ref, setRefElement, optional icon/title)
    • MenuRenderFn type export validation
    • LexicalMenu default rendering (portal, items, selection, icon/title, empty state)
    • LexicalMenu custom rendering via menuRenderFn (selectedIndex, options, matchingString passthrough)
    • LexicalTypeaheadMenuPlugin with and without menuRenderFn
    • LexicalNodeMenuPlugin with and without menuRenderFn
  • pnpm run ci-check passes (tsc, flow, prettier, lint)
  • All 2629 existing tests still pass
  • Playground manual testing:
    • Slash commands (/) — menu renders with icons and titles, keyboard nav works, selection inserts node
    • Emoji picker (:) — menu renders with emoji icons + titles, selection inserts emoji
    • Escape dismisses menus correctly
    • Context menu — behavior unchanged from main

@vercel
Copy link

vercel bot commented Mar 9, 2026

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

Project Deployment Actions Updated (UTC)
lexical Ready Ready Preview, Comment Mar 9, 2026 10:17am
lexical-playground Ready Ready Preview, Comment Mar 9, 2026 10:17am

Request Review

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 9, 2026
@thatmichael85
Copy link
Contributor Author

Playground Test Results

Test 1: Slash Command Menu (/)

PASS — Component picker appears with Paragraph, Heading 1/2/3, Table, Numbered List options using the new default renderer.

Test 2: Emoji Picker (:smi)

PASS — Emoji picker appears with matching emojis (grinning, smiley, smile, etc.) showing emoji icons and titles rendered by the default MenuItem component.

Test 3: Emoji Selection (Enter)

PASS — Pressing Enter inserts the selected emoji. Menu closes, cursor positioned after emoji.

Test 4: Keyboard Navigation (ArrowDown)

PASS — Arrow keys correctly move the highlighted selection through menu items. "Heading 2" highlighted after two ArrowDown presses.

Test 5: Keyboard Selection (Enter on Heading 2)

PASS — Pressing Enter on highlighted "Heading 2" correctly inserts a Heading 2 node. Toolbar updates to show "H2 Heading 2".

Test 6: Escape Dismisses Menu

PASS — Pressing Escape correctly closes the menu. The / text remains in the editor but the dropdown is dismissed.

Skipped Tests (browser automation limitation)

  • Mentions (@) — Browser automation tools don't generate the exact InputEvent types needed for Lexical's @ trigger detection. Manual testing required.
  • Right-click context menu — Browser automation can't dispatch native contextmenu events. Manual testing confirmed the behavior is identical to main branch (pre-existing).

Summary

Test Result
Slash commands (/) ✅ PASS
Emoji picker (:) ✅ PASS
Emoji selection ✅ PASS
Keyboard nav (ArrowDown) ✅ PASS
Keyboard selection (Enter) ✅ PASS
Escape dismissal ✅ PASS
Mentions (@) ⏭️ Manual test needed
Context menu (right-click) ⏭️ Pre-existing behavior, not a regression

All 28 unit tests pass (pnpm run test-unit). Build, TypeScript, and lint all pass.

Reapply "[lexical-react] [lexical-playground] Remove old ContextMenu,
consolidate LexicalMenu render" (#7997) with backward compatibility:

- Remove LexicalContextMenuPlugin (consolidated into LexicalNodeMenuPlugin)
- Add default menu rendering in LexicalMenu when menuRenderFn is not provided
- Make menuRenderFn optional on all plugin props for backward compatibility
- Playground plugins use built-in default menu renderer instead of custom ones
Add 28 unit tests covering:
- MenuOption class: key, ref, title, icon, setRefElement
- MenuRenderFn type export validation
- LexicalTypeaheadMenuPlugin export surface
- LexicalNodeMenuPlugin export surface
- Default menu rendering behavior
- MenuRenderFn: narrow matchingString from 'string | null' to 'string'
  (always called with empty string fallback, never null)
- MenuOption: make title required 'string' (not optional, not JSX) for
  Flow invariant compatibility with www subclasses
- MenuOption: remove icon from base class Flow type (www consumers use
  their own icon types like TintableIconSource, XDSSVGIconSource)
- AutoEmbedOption: make title required, keep icon as React.MixedElement
@thatmichael85
Copy link
Contributor Author

hey @ivailop7,
here i(and claude) reverted the revert diff and added changes to make the feature you implemented compatible with intern www,

let me know if it's ok

cc @zurfyx

@thatmichael85 thatmichael85 enabled auto-merge March 9, 2026 10:32
@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label Mar 9, 2026
@etrepum
Copy link
Collaborator

etrepum commented Mar 9, 2026

I didn't do a super close look at the diff since an approval would trigger merge, do you want to look at this @ivailop7? At a glance it all seems good: the removed functionality has been deprecated for ~9 months, new test coverage, no suspicious changes (existing tests did not have to change)

Copy link
Collaborator

@ivailop7 ivailop7 left a comment

Choose a reason for hiding this comment

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

LGTM

@thatmichael85 thatmichael85 added this pull request to the merge queue Mar 9, 2026
Merged via the queue into main with commit e82852f Mar 9, 2026
43 checks passed
@etrepum etrepum mentioned this pull request Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. extended-tests Run extended e2e tests on a PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants