Skip to content

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.

TypeScript
/* file: app.component.ts */
import { Component } from '@angular/core';
import { GridSettings, HotTableModule } from '@handsontable/angular-wrapper';
@Component({
selector: 'app-example1',
standalone: true,
imports: [HotTableModule],
template: `
<hot-table
[settings]="hotSettings" [data]="hotData">
</hot-table>
`,
})
export class AppComponent {
readonly hotData = [
['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'],
];
readonly hotSettings: GridSettings = {
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
};
}
/* end-file */
/* file: app.config.ts */
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { registerAllModules } from 'handsontable/registry';
import { HOT_GLOBAL_CONFIG, HotGlobalConfig, NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
// register Handsontable's modules
registerAllModules();
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
{
provide: HOT_GLOBAL_CONFIG,
useValue: { license: NON_COMMERCIAL_LICENSE } as HotGlobalConfig,
},
],
};
/* end-file */
HTML
<div>
<app-example1></app-example1>
</div>

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 beforeChange hooks 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:

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:

WindowsmacOSActionExcelSheets
Ctrl+Z+ZUndo the last action
Ctrl+Y+YRedo the last action
Ctrl+Shift+Z++ZRedo the last action

Configuration options

Hooks

Plugins

Microsoft and Excel are registered trademarks of Microsoft Corporation. Google Sheets is a trademark of Google LLC.