Overview
The deleteContentBackward inputType is triggered when the user presses the Backspace key. It deletes the character or content before the cursor position (backward delete).
Basic Behavior
Scenario: Cursor position
Before (Cursor at position 5)
After Backspace key
IME Composition + Backspace
⚠️ Critical Issue
During IME composition, pressing Backspace may cancel the composition or delete more than expected. The behavior varies significantly between browsers and IME implementations.
See: IME & Composition for more details.
Editor Internal Model & DOM Synchronization
⚠️ Exception: preventDefault() and Model Updates
When editors use preventDefault() and update internal models:
- Browser's default deletion is prevented
- Editor deletes from its internal model, then re-renders DOM
- Browser's undo stack may not include the deletion (because default was prevented)
- If editor re-renders entire DOM from model, browser may lose track of what was deleted
- Selection may become invalid after DOM re-render, requiring manual restoration
Best Practice: Always restore selection after model update and DOM re-render to ensure cursor position is correct.
Editor-Specific Handling
Different editor frameworks handle backward deletion differently. Here's how major editors implement deleteContentBackward:
Backward Deletion
Slate uses Transforms.delete() to delete content backward:
import { Editor, Transforms } from 'slate';
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'deleteContentBackward') {
e.preventDefault();
const { selection } = editor;
if (selection && !selection.isCollapsed) {
// Delete selected content
Transforms.delete(editor);
} else if (selection) {
// Delete character before cursor
Transforms.delete(editor, { reverse: true, unit: 'character' });
}
}
});
- Transforms.delete: Deletes content with
reverse: truefor backward deletion. - Unit control: Can delete by character, word, or line.
- Selection handling: Automatically handles collapsed and non-collapsed selections.
Backward Deletion
ProseMirror uses deleteSelection and backspace commands:
import { deleteSelection, backspace } from 'prosemirror-commands';
view.dom.addEventListener('beforeinput', (e) => {
if (e.inputType === 'deleteContentBackward') {
e.preventDefault();
const { state, dispatch } = view;
if (state.selection.empty) {
// Collapsed selection - use backspace command
if (backspace(state, dispatch)) {
// Handled
}
} else {
// Non-collapsed - delete selection
if (deleteSelection(state, dispatch)) {
// Handled
}
}
}
});
- backspace command: Handles backward deletion for collapsed selections.
- deleteSelection command: Handles deletion of selected content.
- Schema-aware: Deletion respects schema constraints and block boundaries.
Backward Deletion
Draft.js uses Modifier.removeRange() to delete content:
import { EditorState, Modifier } from 'draft-js';
function handleDeleteBackward(editorState) {
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
let newSelection = selection;
if (selection.isCollapsed) {
// Move selection backward by one character
newSelection = selection.merge({
anchorOffset: Math.max(0, selection.anchorOffset - 1),
});
}
const newContentState = Modifier.removeRange(
contentState,
newSelection,
'backward'
);
return EditorState.push(
editorState,
newContentState,
'remove-range'
);
}
- Modifier.removeRange: Removes content in the specified range.
- Selection adjustment: For collapsed selection, extends selection backward before deleting.
- ContentState updates: Creates new immutable ContentState with deletion applied.