Phenomenon
In iOS Safari with Korean IME, insertFromComposition events do not fire at all. Composition events (compositionstart, compositionupdate, compositionend) also do not fire. Instead, iOS Safari uses a deleteContentBackward followed by insertText pattern for each composition update. This is likely due to iOS Safari using its own input model for Korean IME.
Reproduction example
- Focus a
contenteditableelement in iOS Safari (iPhone/iPad). - Activate Korean IME.
- Start composing Korean text (e.g., type “ㅎ” then “ㅏ” then “ㄴ” to compose “한”).
- Continue typing to update composition (e.g., type “ㄱ” then “ㅡ” then “ㄹ” to update to “한글”).
- Observe
beforeinputevents -insertFromCompositiondoes NOT fire. - Observe composition events - they do NOT fire.
- Instead, observe
deleteContentBackwardfollowed byinsertTextpattern.
Observed behavior
When composing Korean text:
-
No insertFromComposition events:
insertFromCompositionnever fires- Handlers expecting
insertFromCompositionwill never receive these events
-
No composition events:
compositionstartdoes NOT firecompositionupdatedoes NOT firecompositionenddoes NOT fire- Handlers expecting composition events will never receive them
-
Alternative event pattern:
beforeinputfires withinputType: 'deleteContentBackward'andisComposing: truebeforeinputfires again withinputType: 'insertText'(notinsertCompositionText) andisComposing: true- This pattern repeats for each composition update
-
Result:
- Handlers expecting
insertFromCompositionwill never work - Handlers expecting composition events will never work
- Only handlers that recognize the
deleteContentBackward+insertTextpattern will work
- Handlers expecting
Expected behavior
insertFromCompositionshould fire during composition updates- Composition events should fire during composition
- Standard composition event model should be used
- Behavior should be consistent with other browsers and IMEs
Impact
- Missing event handlers: Handlers expecting
insertFromCompositionwill never receive events - Missing composition handlers: Handlers expecting composition events will never receive events
- Different input model: iOS Safari uses fundamentally different input model for Korean IME
- Platform-specific code required: Different handling logic required for iOS Safari Korean IME
- IME-specific code required: Different handling logic required for Korean vs other IMEs on iOS Safari
Browser Comparison
- iOS Safari (Korean):
insertFromCompositiondoes NOT fire, composition events do NOT fire, usesdeleteContentBackward+insertTextpattern - iOS Safari (Japanese/Kanji):
insertFromCompositionfires, composition events fire - Desktop Safari:
insertFromCompositionfires, composition events fire - Chrome/Edge: Generally uses
insertCompositionTextinstead ofinsertFromComposition, composition events fire - Firefox: Behavior varies but generally more consistent with Chrome
Notes and possible direction for workarounds
-
Handle deleteContentBackward + insertText pattern: Recognize this pattern as composition update:
let lastCompositionDelete = null; element.addEventListener('beforeinput', (e) => { if (e.inputType === 'deleteContentBackward' && e.isComposing) { // Store for pairing with insertText lastCompositionDelete = e; return; } if (e.inputType === 'insertText' && e.isComposing) { // iOS Safari Korean IME: insertFromComposition never fires // Handle as composition update if (lastCompositionDelete) { // Process as single composition update handleCompositionUpdate(e.data); lastCompositionDelete = null; } } }); -
Platform and IME detection: Detect iOS Safari with Korean IME:
const isIOSSafari = /iPhone|iPad|iPod/.test(navigator.userAgent) && /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent); const isKoreanIME = /* detect Korean IME */; if (isIOSSafari && isKoreanIME) { // Use deleteContentBackward + insertText pattern handler // Do not expect insertFromComposition or composition events } -
Do not rely on insertFromComposition: For iOS Safari Korean IME, do not expect
insertFromCompositionevents -
Do not rely on composition events: For iOS Safari Korean IME, do not expect composition events
-
Use isComposing flag: Use
e.isComposingflag to detect composition state instead of composition events