--- title: "Undo & redo" description: "How FlowDrop's undo/redo system works and how to use it programmatically." source: https://flowdrop.io/docs/tutorials/recipes/undo-redo site: FlowDrop documentation --- # Undo & redo FlowDrop provides built-in undo/redo that tracks every workflow change. ## Keyboard Shortcuts | Shortcut | Action | | ---------------------- | ------ | | `Ctrl/Cmd + Z` | Undo | | `Ctrl/Cmd + Shift + Z` | Redo | These work automatically — no configuration needed. ## How It Works FlowDrop's history store takes **snapshots** of the entire workflow state. Each change (node add/remove/move, edge add/remove, config change) pushes a new snapshot onto the undo stack. - **Undo** restores the previous snapshot and pushes the current state onto the redo stack - **Redo** restores the next snapshot from the redo stack - Making a new change after undoing clears the redo stack ## Programmatic Access History lives on the instance — resolve it with `getInstance()` inside the component tree (or use the mount handle's `.instance`): ```typescript import { getInstance } from '@flowdrop/flowdrop/editor'; const fd = getInstance(); // Check availability — reactive getters on historyBindings const canUndo = fd.historyBindings.canUndo; // boolean const canRedo = fd.historyBindings.canRedo; // boolean // Perform undo/redo (HistoryStore actions are bound — safe to detach) fd.historyBindings.undo(); fd.historyBindings.redo(); // Clear history fd.historyBindings.clear(fd.workflow.current); ``` ## Transactions Group multiple changes into a single undo step: ```typescript import { getInstance } from '@flowdrop/flowdrop/editor'; const fd = getInstance(); // Start a transaction fd.historyBindings.startTransaction(fd.workflow.current, 'Rearrange layout'); // Make multiple changes — none are recorded individually fd.workflow.actions.updateNode('node-1', { position: { x: 100, y: 200 } }); fd.workflow.actions.updateNode('node-2', { position: { x: 300, y: 200 } }); fd.workflow.actions.updateNode('node-3', { position: { x: 500, y: 200 } }); // Commit — all changes become one undo step fd.historyBindings.commitTransaction(); // Or cancel — all changes revert // fd.historyBindings.cancelTransaction(); ``` ## Building Custom Undo/Redo Buttons Outside the component tree, hold the mount handle and read `.instance`: ```typescript const app = await mountFlowDropApp(container, options); const fd = app.instance; const undoBtn = document.getElementById('undo'); const redoBtn = document.getElementById('redo'); undoBtn.addEventListener('click', () => fd.historyBindings.undo()); redoBtn.addEventListener('click', () => fd.historyBindings.redo()); // Update button state (polling — for non-Svelte frameworks) setInterval(() => { undoBtn.disabled = !fd.historyBindings.canUndo; redoBtn.disabled = !fd.historyBindings.canRedo; }, 500); ``` In Svelte, resolve the instance and use reactivity instead of polling: ```svelte ``` ## Next Steps - [Store System](/editor/advanced/store-system) — all stores including history - [Event System](/editor/advanced/event-system) — `onWorkflowChange` fires after undo/redo