Overview
The deleteByComposition inputType is triggered when content is deleted during IME (Input Method Editor) composition. This typically occurs when the user presses Backspace or Delete while composing text in languages that require composition, such as Chinese, Japanese, and Korean.
Basic Behavior
Scenario: Deleting during Korean IME composition
During composition (typing "한")
After pressing Backspace during composition
IME Composition Deletion Behavior
⚠️ Critical Issue
During IME composition, pressing Backspace or Delete may cause unexpected behavior:
- Composition may be cancelled entirely
- More text than expected may be deleted (entire syllable or word)
- Composition text may be partially committed before deletion
- Event order may be unpredictable
- Behavior varies significantly between browsers and IME implementations
See: deleteContentBackward and deleteContentForward for similar issues.
Browser-Specific Behavior
Chrome/Edge
- May cancel composition when Backspace is pressed
- May delete entire composition text at once
- Event timing may differ from regular deletion
Firefox
- Similar behavior to Chrome
- May handle composition cancellation differently
Safari
- IME composition deletion behavior may differ, especially on macOS
- May use different event patterns
Editor-Specific Handling
Different editor frameworks handle composition deletion similarly to regular deletion, but need to account for composition state. Here's how major editors implement deleteByComposition:
Composition Deletion Handling
Slate handles composition deletion with composition state awareness:
import { Editor, Transforms } from 'slate';
let isComposing = false;
element.addEventListener('compositionstart', () => {
isComposing = true;
});
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'deleteByComposition') {
e.preventDefault();
const { selection } = editor;
if (selection && !selection.isCollapsed) {
// Delete selected content
Transforms.delete(editor);
} else if (selection) {
// Delete backward during composition
Transforms.delete(editor, { reverse: true, unit: 'character' });
}
}
});
element.addEventListener('compositionend', () => {
isComposing = false;
});
- Composition state: Tracks composition state to handle deletion appropriately.
- Transforms.delete: Uses same deletion method as regular delete operations.
Composition Deletion Handling
ProseMirror handles composition deletion:
import { backspace } from 'prosemirror-commands';
view.dom.addEventListener('compositionstart', () => {
view.composing = true;
});
view.dom.addEventListener('beforeinput', (e) => {
if (e.inputType === 'deleteByComposition') {
e.preventDefault();
const { state, dispatch } = view;
if (state.selection.empty) {
// Use backspace command during composition
if (backspace(state, dispatch)) {
// Handled
}
} else {
// Delete selection
if (deleteSelection(state, dispatch)) {
// Handled
}
}
}
});
view.dom.addEventListener('compositionend', () => {
view.composing = false;
});
- View.composing: Tracks composition state in ProseMirror view.
- backspace command: Uses backspace command for composition deletion.
Composition Deletion Handling
Draft.js handles composition deletion:
import { EditorState, Modifier } from 'draft-js';
let isComposing = false;
element.addEventListener('compositionstart', () => {
isComposing = true;
});
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'deleteByComposition') {
e.preventDefault();
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
// Delete backward during composition
let newSelection = selection;
if (selection.isCollapsed) {
newSelection = selection.merge({
anchorOffset: Math.max(0, selection.anchorOffset - 1),
});
}
const newContentState = Modifier.removeRange(
contentState,
newSelection,
'backward'
);
const newState = EditorState.push(
editorState,
newContentState,
'remove-range'
);
setEditorState(newState);
}
});
element.addEventListener('compositionend', () => {
isComposing = false;
});
- Composition tracking: Tracks composition state to handle deletion.
- Modifier.removeRange: Uses same deletion method as regular delete operations.