Undo & Redo
Spreadsheet implements undo/redo through a CommandManager that maintains a history stack. Every mutating operation (cell edit, resize, merge) is wrapped in a Command object with execute() and undo() methods. Press Ctrl+Z to undo and Ctrl+Y or Ctrl+Shift+Z to redo.
View source code
import { useState, useRef, useCallback } from 'react';import { Spreadsheet } from '@witqq/spreadsheet-react';import type { SpreadsheetRef, CellChangeEvent } from '@witqq/spreadsheet-react';import { DemoWrapper } from './DemoWrapper';import { DemoButton } from './DemoButton';import { DemoToolbar, StatusText } from './DemoToolbar';import { generateEmployees, employeeColumns } from './generate-data';import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(50);
export function UndoRedoDemo() { const { witTheme } = useSiteTheme(); const tableRef = useRef<SpreadsheetRef>(null); const [editCount, setEditCount] = useState(0);
const handleUndo = useCallback(() => tableRef.current?.undo(), []); const handleRedo = useCallback(() => tableRef.current?.redo(), []); const handleCellChange = useCallback((_event: CellChangeEvent) => { setEditCount(prev => prev + 1); }, []);
return ( <DemoWrapper title="Live Demo" description="Double-click to edit cells. Use the buttons or Ctrl+Z / Ctrl+Y to undo and redo." height={440}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <DemoToolbar> <DemoButton onClick={handleUndo}>↩ Undo</DemoButton> <DemoButton onClick={handleRedo}>↪ Redo</DemoButton> <StatusText>Edits: {editCount}</StatusText> </DemoToolbar> <div style={{ flex: 1 }}> <Spreadsheet theme={witTheme} ref={tableRef} columns={employeeColumns} data={data} showRowNumbers editable onCellChange={handleCellChange} style={{ width: '100%', height: '100%' }} /> </div> </div> </DemoWrapper> );}The history stack holds up to 100 commands by default. When the limit is reached, the oldest command is discarded.
Built-in Commands
Section titled “Built-in Commands”| Command | Description |
|---|---|
CellEditCommand | Single cell value change |
BatchCellEditCommand | Multiple cell changes (paste, cut, autofill) |
ResizeColumnCommand | Column width change |
ResizeRowCommand | Row height change |
MergeCellsCommand | Merge a cell region |
UnmergeCellsCommand | Unmerge a cell region |
InsertRowCommand | Insert a row at a given index |
DeleteRowCommand | Delete a row at a given index |
Undo/Redo Buttons
Section titled “Undo/Redo Buttons”Expose undo and redo through toolbar buttons via ref:
import { useRef, useState } from 'react';import { Spreadsheet, SpreadsheetRef } from '@witqq/spreadsheet-react';
function App() { const ref = useRef<SpreadsheetRef>(null); const [canUndo, setCanUndo] = useState(false); const [canRedo, setCanRedo] = useState(false);
return ( <> <button disabled={!canUndo} onClick={() => ref.current?.getInstance().getCommandManager().undo()} > Undo </button> <button disabled={!canRedo} onClick={() => ref.current?.getInstance().getCommandManager().redo()} > Redo </button> <Spreadsheet ref={ref} columns={columns} data={data} editable={true} onCommandExecuted={() => { setCanUndo(ref.current?.getInstance().getCommandManager().canUndo() ?? false); setCanRedo(ref.current?.getInstance().getCommandManager().canRedo() ?? false); }} /> </> );}API Reference
Section titled “API Reference”CommandManager
Section titled “CommandManager”| Method | Signature | Description |
|---|---|---|
execute | (command: Command) => void | Execute and push to history |
undo | () => void | Undo last command |
redo | () => void | Redo last undone command |
canUndo | () => boolean | Whether undo is available |
canRedo | () => boolean | Whether redo is available |
clear | () => void | Clear entire history |
Command Interface
Section titled “Command Interface”interface Command { execute(): void; undo(): void; description: string;}