Overview
The historyRedo inputType is triggered when the user presses Ctrl/Cmd + Shift + Z (or Ctrl/Cmd + Y on some systems). The browser reapplies the last undone operation from its redo stack.
Basic Behavior
Scenario: Redo after undo
Current state (after undo)
After Ctrl/Cmd + Shift + Z (Redo)
Browser Redo Stack
- Browsers maintain a redo stack that stores undone operations
- The redo stack is cleared when a new operation is performed after an undo
- Redo stack depth and behavior varies between browsers
Editor Internal Model & DOM Synchronization
⚠️ Critical Exception: historyRedo May Not Fire
Similar to historyUndo: When editors use internal models and manipulate DOM directly, historyRedo event may not fire or may be ignored.
See historyUndo - Editor Internal Model & DOM Synchronization for detailed explanation of why this happens and how to handle it.
Editor-Specific Handling
Different editor frameworks maintain their own redo stacks, separate from the browser's redo stack. Here's how major editors implement historyRedo:
Redo Operation
Slate uses History.redo() to reapply undone operations:
import { Editor, History } from 'slate';
import { withHistory } from 'slate-history';
const editor = withHistory(createEditor());
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'historyRedo') {
e.preventDefault();
// Slate's History plugin handles redo
History.redo(editor);
}
});
function handleRedo() {
History.redo(editor);
}
- History.redo: Reapplies the last undone operation.
- Operation-based: Reapplies operations from redo stack.
Redo Operation
ProseMirror uses redo command:
import { redo } from 'prosemirror-history';
view.dom.addEventListener('beforeinput', (e) => {
if (e.inputType === 'historyRedo') {
e.preventDefault();
const { state, dispatch } = view;
if (redo(state, dispatch)) {
// Handled
}
}
});
- redo command: Uses
redo()command to reapply last undone transaction. - Transaction-based: Reapplies transactions from redo stack.
Redo Operation
Draft.js uses EditorState.redo() to reapply undone state:
import { EditorState } from 'draft-js';
element.addEventListener('beforeinput', (e) => {
if (e.inputType === 'historyRedo') {
e.preventDefault();
const redoStack = editorState.getRedoStack();
if (!redoStack.isEmpty()) {
const newState = EditorState.redo(editorState);
setEditorState(newState);
}
}
});
function handleRedo() {
const newState = EditorState.redo(editorState);
setEditorState(newState);
}
- EditorState.redo: Uses
EditorState.redo()to reapply previous state. - State-based: Reapplies EditorState snapshots from redo stack.