Overview
The insertText inputType is triggered when the user types regular text characters (not formatting shortcuts). The text is inserted at the current cursor position or replaces selected text.
Basic Behavior
Scenario 1: Cursor position (no selection)
Before (Cursor at position 5)
After typing 'x'
Scenario 2: Text selected
Before (Text selected)
After typing 'x' (Replaces selection)
IME Composition
During IME composition, insertText events may fire multiple times as the user composes characters. The e.data property contains the composed text.
See: IME & Composition for more details.
⚠️ Space Key During Composition
During IME composition, pressing the Space key may behave unexpectedly:
- Space key may be ignored (no space inserted)
- Composition may be committed inconsistently
- Event order may differ from native text controls
- Behavior varies between browsers and IME implementations
This can affect word boundary detection and autocomplete features.
Mobile Keyboard Text Prediction (Android)
⚠️ Android Samsung Keyboard Text Prediction
Android + Samsung Keyboard: When text prediction/suggestion features are enabled on Samsung keyboard, selecting suggested text may cause unexpected behavior:
insertTextevents may fire with the full suggested phrase instead of individual characters- Multiple
inputevents may fire for a single suggestion selection - The
beforeinputevent may not fire before suggestion insertion - Suggested text may replace more content than expected (entire words instead of partial words)
- Event timing may differ from manual typing, making it difficult to track changes accurately
Impact: Text prediction can interfere with custom editing logic, undo/redo stacks, and change tracking systems.
Workaround
To handle text prediction issues:
- Monitor both
beforeinputandinputevents to catch all text insertions - Compare DOM state before and after events to detect bulk text insertions
- Use
e.dataproperty to identify suggested text vs manual typing - Consider disabling text prediction via
autocomplete="off"orspellcheck="false"if it interferes with your use case
Editor Internal Model & DOM Synchronization
⚠️ Exception: preventDefault() and Model Updates
When editors use preventDefault() and update internal models:
- Browser's default text insertion is prevented
- Editor inserts text into its internal model, then re-renders DOM
- Browser's undo stack may not include the text insertion (because default was prevented)
- If editor re-renders DOM from model, browser may not recognize the text as user-inserted
- Subsequent undo operations may not work correctly if browser and editor undo stacks are out of sync
Best Practice: Always maintain your own undo stack when using preventDefault() on text insertion events.
Editor-Specific Handling
Different editor frameworks handle text insertion differently. Here's how major editors implement insertText:
Text Insertion
Slate uses Transforms.insertText() to insert text at the current selection:
import { Editor, Transforms } from 'slate';
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'insertText' && e.data) {
e.preventDefault();
Transforms.insertText(editor, e.data);
}
});
// Or handle in input event for composition
element.addEventListener('input', (e) => {
const inputEvent = e as InputEvent;
if (inputEvent.inputType === 'insertText' && inputEvent.data) {
// Slate may have already handled this, but you can sync if needed
// Check editor state and update if necessary
}
});
- Transforms.insertText: Inserts text at the current selection position.
- Selection handling: Automatically handles collapsed and non-collapsed selections.
- Composition support: Can handle IME composition through multiple insertText events.
Text Insertion
ProseMirror uses commands to insert text:
import { insertText } from 'prosemirror-commands';
// In keymap or beforeinput handler
view.dom.addEventListener('beforeinput', (e) => {
if (e.inputType === 'insertText' && e.data) {
e.preventDefault();
const { state, dispatch } = view;
if (insertText(state, e.data, state.selection.$from.marks(), dispatch)) {
// Handled
}
}
});
// ProseMirror also handles text input through its own input handling
// which integrates with the editor state and schema
- insertText command: Inserts text with current marks applied.
- Schema integration: Text insertion respects schema constraints.
- Transaction-based: All changes are applied as transactions for undo/redo support.
Text Insertion
Draft.js uses Modifier.insertText() to insert text:
import { EditorState, Modifier } from 'draft-js';
function handleInsertText(editorState, text) {
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
const newContentState = Modifier.insertText(
contentState,
selection,
text,
editorState.getCurrentInlineStyle()
);
return EditorState.push(
editorState,
newContentState,
'insert-characters'
);
}
// In beforeinput handler
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'insertText' && e.data) {
e.preventDefault();
const newState = handleInsertText(editorState, e.data);
setEditorState(newState);
}
});
- Modifier.insertText: Inserts text into ContentState with current inline styles.
- ContentState: Text is stored in immutable ContentState objects.
- Style preservation: Current inline styles are applied to inserted text.