Scenario

Typing certain characters makes cursor jump on Chrome Mobile

On Chrome Mobile for Android, typing certain punctuation characters (commas, colons, semicolons, quotes, etc.) in the middle of a word causes the cursor to jump to the end of the word instead of staying at the insertion point.

selection
Scenario ID
scenario-caret-jump-chrome-mobile

Details

On Chrome Mobile for Android, typing certain punctuation characters in the middle of a word causes the cursor to unexpectedly jump to the end of the word instead of staying at the insertion point.

Problem Description

This issue occurs when:

  1. User is on Chrome Mobile for Android
  2. User has typed a word (e.g., “California”)
  3. User inserts specific punctuation characters in the middle of the word

Characters that trigger the jump

, : ; ! ? " ' & +() {} [] \ | = and similar punctuation

Expected Behavior

  • Cursor should stay at the insertion point (where the punctuation was typed)
  • User should be able to continue typing from that position

Actual Behavior (Chrome Mobile Bug)

  • Cursor jumps to end: Cursor moves to the end of the entire word
  • Must manually reposition: User has to tap to correct position to continue typing
  • Makes editing impossible: Continuous editing with these characters becomes very difficult

Affected Browsers

  • Chrome for Android - Issue confirmed
  • Desktop Chrome - Does NOT exhibit this behavior
  • Firefox Mobile - Does NOT exhibit this behavior
  • Safari (iOS) - Does NOT exhibit this behavior

Root Cause

Chrome Mobile’s caret positioning algorithm appears to have a bug when:

  1. Processing specific punctuation characters
  2. Calculating insertion point in middle of existing text
  3. The calculation fails and places cursor at end of word instead of insertion point

Workarounds

  1. Use setTimeout before continuing typing:

    editor.addEventListener('input', (e) => {
      const selection = window.getSelection();
      const range = selection.getRangeAt(0);
      
      // Store insertion position
      const insertionPoint = {
        node: range.startContainer,
        offset: range.startOffset
      };
      
      setTimeout(() => {
        // Try to restore position
        const newRange = document.createRange();
        newRange.setStart(insertionPoint.node, insertionPoint.offset);
        newRange.collapse(true);
        selection.removeAllRanges();
        selection.addRange(newRange);
      }, 0);
    });
  2. Use beforeinput event to detect jump:

    let lastCaretPosition = null;
    
    editor.addEventListener('beforeinput', (e) => {
      const selection = window.getSelection();
      if (selection.rangeCount > 0) {
        lastCaretPosition = {
          node: selection.getRangeAt(0).startContainer,
          offset: selection.getRangeAt(0).startOffset
        };
      }
    });
    
    editor.addEventListener('input', (e) => {
      const selection = window.getSelection();
      if (selection.rangeCount > 0 && lastCaretPosition) {
        const currentOffset = selection.getRangeAt(0).startOffset;
        const distance = Math.abs(currentOffset - lastCaretPosition.offset);
        
        // If cursor jumped significantly
        if (distance > 2) {
          console.warn('Cursor jump detected');
          // Restore position
          const range = document.createRange();
          range.setStart(lastCaretPosition.node, lastCaretPosition.offset);
          range.collapse(true);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      }
    });
  3. User education: Add UI hint that these characters may cause issues on mobile Chrome

  4. Use desktop browser: Recommend users use desktop browsers for editing when possible

References

Scenario flow

Visual view of how this scenario connects to its concrete cases and environments. Nodes can be dragged and clicked.

React Flow mini map

Variants

Each row is a concrete case for this scenario, with a dedicated document and playground.

Case OS Device Browser Keyboard Status
ce-0269-caret-jump-chrome-mobile-ios-en iOS 16+ Mobile (iPhone/iPad) Any Safari 16+ English (QWERTY) confirmed
ce-0270-caret-jump-chrome-mobile-firefox-en Windows 10/11 Desktop Any Firefox 120+ English (QWERTY) confirmed

Browser compatibility

This matrix shows which browser and OS combinations have documented cases for this scenario. Click on a cell to view the specific case.

Confirmed
Draft
No case documented

Cases

Open a case to see the detailed description and its dedicated playground.

Related Scenarios

Other scenarios that share similar tags or category.

Tags: caret, cursor, chrome

Text caret is invisible on position:relative elements

When editing content inside an element with `position:relative`, the text caret (cursor) is completely invisible. Text can be typed and appears in the editor, but there's no visual feedback of where the insertion point is located.

2 cases
Tags: caret, cursor, chrome

Caret jumps to end when deleting character next to non-editable element

When deleting the last character before a non-editable "pill" or tag element (contenteditable="false") in a contenteditable div in Chrome, the caret (cursor) jumps to the end of the entire contenteditable div instead of staying adjacent to the remaining content.

1 case
Tags: caret

Browser zoom causes caret and selection positioning issues

When the browser is zoomed (or content is scaled via CSS transforms), caret position and text selection in contenteditable elements can become inaccurate. Clicking at a certain position places the caret elsewhere, and selection highlights may not match the visual selection.

1 case
Tags: cursor

Cursor disappears with contenteditable="false" elements

When contenteditable='false' elements are placed inside a contenteditable container, the cursor may disappear or become invisible in certain browsers, making it difficult for users to determine the text insertion point.

0 cases

Comments & Discussion

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