Case ce-0215-ime-insertfromcomposition-targetranges-ios-safari-japanese · Scenario scenario-ime-insertfromcomposition-targetranges

insertFromComposition targetRanges are collapsed and need recalculation in iOS Safari

OS: iOS 17.0+ Device: iPhone or iPad Any Browser: Safari 17.0+ Keyboard: Japanese (IME) Status: draft
composition ime beforeinput insertFromComposition targetRanges ios safari japanese

Phenomenon

In iOS Safari with Japanese/Kanji IME, insertFromComposition fires with collapsed targetRanges that do not accurately represent the insertion point. Recalculating ranges based on current selection is necessary to correctly position the composition text.

Reproduction example

  1. Focus a contenteditable element in iOS Safari (iPhone/iPad).
  2. Activate Japanese IME.
  3. Start composing Japanese/Kanji text (e.g., type “に” then “ほ” then “ん” to compose “日本”).
  4. Continue typing to update composition or convert to Kanji.
  5. Observe beforeinput events with inputType: 'insertFromComposition'.
  6. Check getTargetRanges() - they are collapsed (startOffset === endOffset) but do not represent the correct insertion point.
  7. If handlers trust targetRanges as-is, text will be inserted at wrong position.
  8. Recalculating based on current selection produces correct positioning.

Observed behavior

When updating Japanese/Kanji composition text:

  1. beforeinput event:

    • inputType: 'insertFromComposition'
    • isComposing: true
    • data: '日本' (the new composition text)
    • getTargetRanges() returns collapsed ranges (startOffset === endOffset)
    • The collapsed ranges do NOT accurately represent where the composition text should be inserted
  2. If ranges are trusted as-is:

    • Text may be inserted at wrong location
    • Composition text may appear before or after the intended position
    • Composition updates may fail or produce incorrect results
  3. If ranges are recalculated:

    • Using window.getSelection() to get current selection position
    • Recalculating insertion point based on current selection
    • Text is inserted at correct position
    • Composition updates work correctly

Expected behavior

  • targetRanges from insertFromComposition should accurately represent the insertion point
  • If targetRanges are collapsed and inaccurate, recalculation should be possible
  • Handlers should be able to use current selection to determine correct insertion point
  • Composition text should be inserted at the correct position

Impact

  • Incorrect positioning: Handlers that trust collapsed targetRanges as-is will insert text at wrong positions
  • Composition breakage: Composition updates may fail or produce incorrect results
  • Platform-specific bugs: Code that works on Desktop Safari may fail on iOS Safari
  • IME-specific bugs: Code that works with Korean IME may fail with Japanese/Kanji IME

Browser Comparison

  • iOS Safari (Japanese/Kanji): insertFromComposition fires with collapsed targetRanges that need recalculation
  • Desktop Safari: insertFromComposition fires with accurate collapsed targetRanges (trust as-is)
  • iOS Safari (Korean): insertFromComposition does NOT fire
  • Chrome/Edge: Generally uses insertCompositionText instead of insertFromComposition
  • Firefox: Behavior varies but generally more consistent with Chrome

Notes and possible direction for workarounds

  • Recalculate collapsed ranges: Recalculate based on current selection in iOS Safari:

    element.addEventListener('beforeinput', (e) => {
      if (e.inputType === 'insertFromComposition') {
        const targetRanges = e.getTargetRanges?.() || [];
        if (targetRanges.length > 0) {
          const range = targetRanges[0];
          if (range.collapsed) {
            // Recalculate based on current selection
            const selection = window.getSelection();
            const currentRange = selection?.rangeCount ? selection.getRangeAt(0) : null;
            if (currentRange) {
              // Use currentRange instead of targetRanges
              handleCompositionInsertion(currentRange);
            }
          } else {
            // Use targetRanges as-is if not collapsed
            handleCompositionInsertion(range);
          }
        }
      }
    });
  • Platform and IME detection: Detect iOS Safari with Japanese/Kanji IME:

    const isIOSSafari = /iPhone|iPad|iPod/.test(navigator.userAgent) && /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
    const isJapaneseIME = /* detect Japanese IME */;
    
    if (isIOSSafari && isJapaneseIME && e.inputType === 'insertFromComposition') {
      // Recalculate collapsed ranges
    }
  • Use current selection: Always use window.getSelection() to get accurate position when targetRanges are collapsed

Before

Hello

Japanese composition in progress
After (Bug - not recalculated)

Hello

If ranges are not recalculated, text is inserted at wrong position
vs
✅ Expected (recalculated)

Hello 日本

Recalculating based on current selection produces correct positioning

Browser compatibility matrix

This matrix shows which browser and OS combinations have documented cases for this scenario. The current case is highlighted. Click on a cell to view other cases.

Current case
Confirmed
Draft
No case documented

All variants (detailed table)

Complete list of all cases for this scenario with full environment details.

Case OS Device Browser Keyboard Status
ce-0214-ime-insertfromcomposition-targetranges-desktop-safari-korean macOS 14.0+ Desktop or Laptop Any Safari 17.0+ Korean (IME) draft
ce-0215-ime-insertfromcomposition-targetranges-ios-safari-japanese iOS 17.0+ iPhone or iPad Any Safari 17.0+ Japanese (IME) draft
ce-0216-ime-insertfromcomposition-missing-ios-safari-korean iOS 17.0+ iPhone or iPad Any Safari 17.0+ Korean (IME) draft

Playground for this case

Use the reported environment as a reference and record what happens in your environment while interacting with the editable area.

Reported environment
OS: iOS 17.0+
Device: iPhone or iPad Any
Browser: Safari 17.0+
Keyboard: Japanese (IME)
Your environment
Sample HTML:
Event log
Use this log together with the case description when filing or updating an issue.
0 events
Interact with the editable area to see events here.

Comments & Discussion

Have questions, suggestions, or want to share your experience? Join the discussion below.