Phenomenon
In Safari desktop on macOS, when preventDefault() is called on keydown or beforeinput events to prevent insertParagraph (Enter key), the Chinese IME composition state becomes corrupted. After this occurs, subsequent Chinese text input fails to work correctly. The input event may not fire properly, Chinese characters may not be inserted, or the composition state may remain in an inconsistent state.
Reproduction example
- Create a contenteditable div and focus it.
- Add event listeners for
keydownand/orbeforeinputthat calle.preventDefault()when Enter is pressed orinputType === "insertParagraph". - Type Chinese text using IME (e.g., “你好”).
- Press Enter key.
- Observe that
preventDefault()successfully prevents the paragraph insertion. - Try to type more Chinese text (e.g., “谢谢”).
- Observe that the Chinese characters are not inserted, or the
inputevent does not fire properly.
Observed behavior
- preventDefault() on insertParagraph: Successfully prevents paragraph insertion when called in
keydownorbeforeinput. - Subsequent IME input failure: After preventing insertParagraph, Chinese IME input stops working.
- Missing input events: The
inputevent may not fire for subsequent Chinese text input. - Composition events:
compositionstart,compositionupdate,compositionendmay not fire correctly. - Character insertion failure: Typed Chinese characters do not appear in the contenteditable element.
- IME state corruption: The IME composition state becomes inconsistent and cannot recover without blurring and refocusing the element.
Expected behavior
preventDefault()should prevent paragraph insertion without affecting IME composition state.- After preventing insertParagraph, subsequent Chinese IME input should continue to work normally.
- The
inputevent should fire correctly for all IME input, regardless of whether insertParagraph was previously prevented. - IME composition state should remain consistent and functional.
Analysis
This issue occurs because Safari’s internal IME composition state management becomes corrupted when insertParagraph is prevented. The browser’s coordination between paragraph insertion and composition state transitions is disrupted, leaving the IME in an inconsistent state.
According to the Input Events Level 2 specification, composition-related input events are not cancelable, but canceling insertParagraph may interfere with the composition lifecycle, especially when Enter is pressed during or after IME composition.
Workarounds
Check isComposing before preventing
Only prevent insertParagraph when not composing:
editor.addEventListener('beforeinput', (e) => {
if (e.inputType === 'insertParagraph' && !e.isComposing) {
e.preventDefault();
// Custom paragraph insertion logic
}
});
Handle Enter in keydown with composition check
editor.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.isComposing) {
e.preventDefault();
// Custom paragraph insertion
}
});
Reset IME state if corrupted
If composition state is already corrupted, blur and refocus the element:
function resetIMEState(editor) {
editor.blur();
setTimeout(() => {
editor.focus();
}, 0);
}
Browser Comparison
- Safari (Desktop macOS): This issue occurs. Preventing insertParagraph breaks subsequent Chinese IME input.
- Chrome: Needs verification
- Firefox: Needs verification
- Edge: Needs verification