-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Bug: LexicalTypeaheadMenuPlugin closes typeahead menu during IME composition #7985
Description
Lexical version: 0.38.2
Steps To Reproduce
- Open any plugin that uses LexicalTypeaheadMenuPlugin. (e.g. CopmponentPickerPlugin, EmojiPickerPlugin ...)
- Modify the plugin to always render menu (remove
options.lengthcheck) - Add "No results found" UI for empty results
- Type Korean characters
ㄱㄱㄱㄱㄱrapidly - Observe "No results found" UI flickering on/off
- Check console logs showing
onClose→onOpencycles witheditor.isComposing() === true
Link to code example:
<LexicalTypeaheadMenuPlugin<ComponentPickerOption>
onQueryChange={setQueryString}
onSelectOption={onSelectOption}
triggerFn={checkForTriggerMatch}
options={options}
onOpen={() => {
console.log('Menu opened');
}}
onClose={() => {
console.log('Menu closed, isComposing:', editor.isComposing());
}}
menuRenderFn={(
anchorElementRef,
{selectedIndex, selectOptionAndCleanUp, setHighlightedIndex},
) =>
anchorElementRef.current
? ReactDOM.createPortal(
<div className="typeahead-popover component-picker-menu">
<ul>
{options.map((option, i: number) => (
<ComponentPickerMenuItem
index={i}
isSelected={selectedIndex === i}
onClick={() => {
setHighlightedIndex(i);
selectOptionAndCleanUp(option);
}}
onMouseEnter={() => {
setHighlightedIndex(i);
}}
key={option.key}
option={option}
/>
))}
{options.length === 0 && (
<li>
<span className="text">No results found</span>
</li>
)}
</ul>
</div>,
anchorElementRef.current,
)
: null
}
/>
The current behavior
During IME composition for Korean, Japanese, or Chinese input, the typeahead menu closes intermittently while typing, even though the trigger character (e.g., @, /)
Root Cause:
During IME composition, the browser creates a range selection (non-collapsed) to display the composing text. Lexical synchronizes this DOM selection state, causing selection.isCollapsed() to return false. The plugin's updateListener doesn't check for composition state before evaluating selection, leading to premature menu closure.
The expected behavior
During IME composition, the typeahead menu should remain stable:
No unexpected onClose → onOpen cycles
"No results found" UI should not flicker
Menu state should only update after composition ends (compositionend event)
Impact of fix
Severity: Medium - Affects user experience but doesn't cause data loss
Frequency: Occurs consistently when using IME input (Korean, Japanese, Chinese, etc.) with any typeahead plugin
Affected users:
- All users typing in CJK (Chinese, Japanese, Korean) languages
- Approximately 1.5+ billion people use these languages globally
- Affects all plugins using LexicalTypeaheadMenuPlugin
Proposed Solution:
// LexicalTypeaheadMenuPlugin.tsx
const updateListener = () => {
editor.getEditorState().read(() => {
if (!editor.isEditable()) {
closeTypeahead();
return;
}
// Skip checks during IME composition
if (editor.isComposing()) {
return;
}
// ... existing logic
});
};