Undo and redo
Revert and restore your changes, using the undo and redo features.
Overview
The UndoRedo plugin records supported grid operations and stores them in undo and redo stacks.
You can use keyboard shortcuts or call API methods to move backward and forward through that history.
The plugin is enabled by default.
Basic demo
Make a few edits in the grid.
Press Ctrl/⌘+Z to undo your last action.
Press Ctrl/⌘+Y (or Ctrl/⌘+Shift+Z) to redo it.
import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { return ( <HotTable data={[ ['Ana García', 'Engineering', 'Senior Engineer', 95000, '2026-03-14'], ['James Okafor', 'Marketing', 'Product Manager', 88000, '2026-07-01'], ['Li Wei', 'Engineering', 'Frontend Dev', 82000, '2026-01-10'], ['Maria Santos', 'HR', 'HR Specialist', 71000, '2026-11-20'], ['David Kim', 'Engineering', 'Backend Dev', 85000, '2026-08-05'], ['Emma Wilson', 'Marketing', 'SEO Analyst', 68000, '2026-02-14'], ['Ahmed Hassan', 'Finance', 'Controller', 92000, '2026-06-30'], ['Sara Johansson', 'Engineering', 'QA Engineer', 78000, '2026-09-12'], ['Carlos Mendez', 'Sales', 'Account Manager', 74000, '2026-04-25'], ]} rowHeaders={true} colHeaders={true} stretchH="all" height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { return ( <HotTable data={[ ['Ana García', 'Engineering', 'Senior Engineer', 95000, '2026-03-14'], ['James Okafor', 'Marketing', 'Product Manager', 88000, '2026-07-01'], ['Li Wei', 'Engineering', 'Frontend Dev', 82000, '2026-01-10'], ['Maria Santos', 'HR', 'HR Specialist', 71000, '2026-11-20'], ['David Kim', 'Engineering', 'Backend Dev', 85000, '2026-08-05'], ['Emma Wilson', 'Marketing', 'SEO Analyst', 68000, '2026-02-14'], ['Ahmed Hassan', 'Finance', 'Controller', 92000, '2026-06-30'], ['Sara Johansson', 'Engineering', 'QA Engineer', 78000, '2026-09-12'], ['Carlos Mendez', 'Sales', 'Account Manager', 74000, '2026-04-25'], ]} rowHeaders={true} colHeaders={true} stretchH="all" height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;What UndoRedo tracks
UndoRedo tracks operations that emit dedicated hooks and register an action in the plugin.
The built-in tracked actions include:
- Cell value changes (
beforeChange) - Row and column insertion/removal (
afterCreateRow,afterCreateCol,beforeRemoveRow,beforeRemoveCol) - Column sorting (
beforeColumnSort) - Filtering (
beforeFilter) - Row and column moving (
beforeRowMove,beforeColumnMove) - Merge and unmerge (
beforeMergeCells,afterUnmergeCells) - Alignment changes (
beforeCellAlignment)
Batch edits and multi-cell changes
For data edits, UndoRedo records only effective changes:
- Entries nullified by other
beforeChangehooks are skipped. - If a single cell changed, UndoRedo restores selection to that cell.
- If multiple cells changed in one operation, UndoRedo restores the full selection range.
When you undo a data-change action, Handsontable can also remove rows or columns that were created as a side effect of that edit, and then restore the previous selection.
Hooks and stack lifecycle
UndoRedo exposes hooks for both stack updates and action execution:
- Stack update hooks:
beforeUndoStackChange,afterUndoStackChange,beforeRedoStackChange, andafterRedoStackChange. - Action hooks:
beforeUndo,afterUndo,beforeRedo, andafterRedo.
You can return false from beforeUndoStackChange, beforeUndo, or beforeRedo to block recording or execution.
Calling loadData() clears both stacks.
Programmatic control
Use the plugin instance to inspect and control history:
const undoRedo = hot.getPlugin('undoRedo');
if (undoRedo.isUndoAvailable()) { undoRedo.undo();}
if (undoRedo.isRedoAvailable()) { undoRedo.redo();}
undoRedo.clear();Registering a custom undoable action
Use done() to add an action to the undo stack that isn’t tracked by default, such as a direct setCellMeta() update.
Call done() with a function that returns an action object. The action object needs an undo() method and a redo() method, each receiving the Handsontable instance and a callback to call once the operation finishes.
function setCellBackgroundColor(row, col, className) { const undoRedo = hot.getPlugin('undoRedo'); const previousClassName = hot.getCellMeta(row, col).className;
undoRedo.done(() => ({ actionType: 'cellBackgroundColor', undo(instance, callback) { instance.setCellMeta(row, col, 'className', previousClassName); instance.render(); callback(); }, redo(instance, callback) { instance.setCellMeta(row, col, 'className', className); instance.render(); callback(); }, }), 'cellBackgroundColor');
hot.setCellMeta(row, col, 'className', className); hot.render();}After you call setCellBackgroundColor(), pressing Ctrl/⌘+Z reverts the color change, and pressing Ctrl/⌘+Y reapplies it.
Known limitations
UndoRedo does not record every possible operation.
The following operations are not tracked by default:
- Column resizing and row resizing
- Hiding columns and hiding rows
- Trimming rows
- Generic cell metadata changes that don’t register an UndoRedo action (for example, most direct
setCellMeta()updates)
Related keyboard shortcuts
| Windows | macOS | Action | Excel | Sheets |
|---|---|---|---|---|
| Ctrl+Z | ⌘+Z | Undo the last action | ✓ | ✓ |
| Ctrl+Y | ⌘+Y | Redo the last action | ✓ | ✓ |
| Ctrl+Shift+Z | ⌘+⇧+Z | Redo the last action | ✓ | ✓ |
Related blog articles
Related API reference
Configuration options
Hooks
Plugins
Microsoft and Excel are registered trademarks of Microsoft Corporation. Google Sheets is a trademark of Google LLC.