deleteContentBackward

How deleteContentBackward inputType deletes content backward (Backspace key) and varies across browsers.

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)

HTML:
<p>Hello|world</p>

After Backspace key

HTML:
<p>Hell|world</p>
Character before cursor deleted

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:

Slate.js

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: true for backward deletion.
  • Unit control: Can delete by character, word, or line.
  • Selection handling: Automatically handles collapsed and non-collapsed selections.
ProseMirror

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.
Draft.js

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.

Related resources