The Action System is Excalidraw's centralized mechanism for executing user commands that modify elements or application state. It provides a declarative way to define operations (drawing, editing, canvas manipulation) with built-in support for keyboard shortcuts, UI rendering, undo/redo tracking, and event analytics.
For information about the History system that consumes action updates, see History and Undo/Redo. For UI components that trigger actions, see UI Components and Toolbar.
The Action System serves as a unified interface between user interactions (keyboard, toolbar clicks, menu selections) and state mutations. Each action encapsulates:
This architecture decouples command logic from UI presentation, enabling actions to be triggered from multiple contexts (toolbar, keyboard, command palette) while maintaining consistent behavior.
Sources: packages/excalidraw/actions/actionProperties.tsx1-300 packages/excalidraw/actions/register.ts
Actions are registered using the register() function, which accepts an object conforming to the Action interface:
Sources: packages/excalidraw/actions/actionProperties.tsx300-355 packages/excalidraw/actions/register.ts
| Property | Type | Purpose |
|---|---|---|
name | string | Unique identifier used to reference the action |
label | string | function | Display text in UI (can be dynamic based on state) |
perform | function | Execution logic returning { elements?, appState?, captureUpdate } |
icon | ReactNode | function | Icon for toolbar/menu (can be state-dependent) |
keyTest | function | Tests if keyboard event should trigger action |
PanelComponent | React.Component | Optional UI component for action configuration |
trackEvent | object | boolean | Analytics tracking configuration |
predicate | function | Determines if action should be visible/enabled |
viewMode | boolean | Whether action is available in view-only mode |
Sources: packages/excalidraw/actions/actionProperties.tsx300-355 packages/excalidraw/actions/actionCanvas.tsx54-90
Sources: packages/excalidraw/actions/actionProperties.tsx300-355
Diagram: Action Execution Sequence
Sources: packages/excalidraw/actions/actionProperties.tsx300-355 packages/excalidraw/actions/actionFinalize.tsx49-310 packages/excalidraw/components/Actions.tsx130-307
The perform function is the core of each action, defined as type ActionFn in packages/excalidraw/actions/types.ts35-40:
Type Signature:
Parameters:
elements - Current element array (ordered)appState - Current application state (immutable)formData - Action-specific data (from UI controls or keyboard)app - App instance with scene, actionManager, props, etc.Returns (ActionResult):
The function can return false to prevent execution (e.g., when preconditions aren't met).
Sources: packages/excalidraw/actions/types.ts24-40 packages/excalidraw/actions/actionProperties.tsx151-212 packages/excalidraw/actions/actionFinalize.tsx49-310
The CaptureUpdateAction enum controls how action results are recorded in the undo/redo history:
Sources: packages/excalidraw/actions/actionProperties.tsx294-327 packages/common/src/constants.ts1-546
| Mode | Use Case | Example |
|---|---|---|
IMMEDIATELY | Discrete, undoable operations | Delete element, change stroke width, finalize drawing |
EVENTUALLY | Continuous operations that should batch | Color picker sliding, opacity dragging, intermediate zoom |
NEVER | Transient state that shouldn't be undone | Opening/closing popups, hover states |
Example Usage:
Sources: packages/excalidraw/actions/actionProperties.tsx294-327 packages/excalidraw/actions/actionProperties.tsx686-708 packages/excalidraw/actions/actionProperties.tsx848-1042
Actions are rendered into UI components through ActionManager.renderAction(). The method accepts an action name and returns the action's PanelComponent with injected props (elements, appState, updateData, app).
Diagram: UI Integration Pattern
When renderAction(actionName) is called:
Lookup: ActionManager retrieves action by name from registry
Predicate Check: Evaluates action.predicate() to determine visibility
Component Render: Calls action.PanelComponent with props:
elements: ExcalidrawElement[]appState: AppStateupdateData: (value) => void - Triggers action executionapp: AppClassPropertiesdata?: any - Optional additional dataUser Interaction: User modifies value in PanelComponent
Execute: updateData calls ActionManager.executeAction(action, "ui")
Sources: packages/excalidraw/components/Actions.tsx130-307 packages/excalidraw/actions/actionProperties.tsx329-358
Actions can define predicate functions to control when they appear:
UI components use helper functions to determine which actions to show:
Sources: packages/excalidraw/components/Actions.tsx93-124 packages/excalidraw/actions/actionCanvas.tsx54-90
The most common action pattern involves modifying element properties. The system provides helper functions for this:
This helper:
Sources: packages/excalidraw/actions/actionProperties.tsx151-172
This helper determines what value to display in UI controls by:
Sources: packages/excalidraw/actions/actionProperties.tsx174-212
Excalidraw organizes actions into functional categories, each implemented in separate files under packages/excalidraw/actions/
Diagram: Action Categories and File Organization
Sources: packages/excalidraw/actions/actionProperties.tsx300-1200 packages/excalidraw/actions/actionCanvas.tsx54-603 packages/excalidraw/actions/actionDeleteSelected.tsx206-329 packages/excalidraw/actions/actionDuplicateSelection.tsx32-130 packages/excalidraw/actions/actionFlip.ts36-85
Actions that modify visual properties of elements:
| Action Name | Purpose | File Location |
|---|---|---|
changeStrokeColor | Modify element stroke color | actionProperties.tsx300-355 |
changeBackgroundColor | Modify element background color | actionProperties.tsx357-435 |
changeFillStyle | Change fill pattern (solid/hachure/cross-hatch) | actionProperties.tsx437-515 |
changeStrokeWidth | Modify stroke thickness | actionProperties.tsx517-573 |
changeSloppiness | Adjust hand-drawn roughness | actionProperties.tsx575-629 |
changeStrokeStyle | Set line style (solid/dashed/dotted) | actionProperties.tsx631-684 |
changeOpacity | Modify element transparency | actionProperties.tsx686-708 |
changeFontSize | Change text size | actionProperties.tsx710-788 |
changeFontFamily | Change text font | actionProperties.tsx848-1042 |
Sources: packages/excalidraw/actions/actionProperties.tsx300-1200
Actions that affect element existence and state:
| Action | Trigger | Behavior |
|---|---|---|
actionFinalize | Escape, Enter, pointer up | Completes multi-point drawing, binds arrows, closes loops |
actionDeleteSelected | Delete, Backspace | Removes selected elements, handles bound text, updates frames |
actionDuplicateSelection | Ctrl+D | Copies selected elements with offset positioning |
Sources: packages/excalidraw/actions/actionFinalize.tsx49-329 packages/excalidraw/actions/actionDeleteSelected.tsx33-329 packages/excalidraw/actions/actionDuplicateSelection.tsx31-121
Actions that modify viewport and canvas-level state:
| Action | Shortcut | Purpose |
|---|---|---|
actionZoomIn | Ctrl/Cmd++ | Increase zoom level by ZOOM_STEP (0.1) |
actionZoomOut | Ctrl/Cmd+- | Decrease zoom level by ZOOM_STEP |
actionResetZoom | Ctrl/Cmd+0 | Reset zoom to 100% |
actionZoomToFit | Shift+1 | Fit all elements in viewport (max 100% zoom) |
actionZoomToFitSelection | Shift+3 | Fit selected elements, zooming beyond 100% |
actionToggleTheme | Alt+Shift+D | Switch between light/dark themes |
actionClearCanvas | - | Delete all elements and reset state |
actionToggleEraserTool | E | Activate/deactivate eraser tool |
actionToggleHandTool | H | Activate/deactivate hand/pan tool |
Sources: packages/excalidraw/actions/actionCanvas.tsx133-603
Actions define keyboard shortcuts through the keyTest property, which is called for every keydown event to determine if the action should execute.
Diagram: Keyboard Event Handling
Simple Key Combination:
Multiple Key Codes:
State-Dependent:
Used from @excalidraw/common/constants.ts:
| Constant | Keys | Usage |
|---|---|---|
KEYS.CTRL_OR_CMD | Ctrl (Win/Linux) or Cmd (Mac) | Modifier for shortcuts |
KEYS.ESCAPE | Escape | Cancel operations |
KEYS.ENTER | Enter | Finalize operations |
KEYS.DELETE | Delete | Delete elements |
KEYS.BACKSPACE | Backspace | Delete elements |
CODES.EQUAL | "Equal" | Zoom in |
CODES.MINUS | "Minus" | Zoom out |
Sources: packages/excalidraw/actions/actionCanvas.tsx169-172 packages/excalidraw/actions/actionDuplicateSelection.tsx109 packages/excalidraw/actions/actionDeleteSelected.tsx316-318 packages/common/src/constants.ts78-110
Actions can modify their behavior based on current state:
Sources: packages/excalidraw/actions/actionFinalize.tsx49-310
While perform is synchronous, actions can trigger async side effects:
Sources: packages/excalidraw/actions/actionProperties.tsx1016-1038
Actions can coordinate multiple element mutations:
Sources: packages/excalidraw/actions/actionFlip.ts36-207
The Action System provides:
Key interfaces:
register() - Registers action definitions with ActionManagerperform() - Executes action logic and returns updatesrenderAction() - Renders action UI componentCaptureUpdateAction - Controls history recording behaviorSources: packages/excalidraw/actions/actionProperties.tsx1-1200 packages/excalidraw/actions/actionCanvas.tsx1-603 packages/excalidraw/actions/actionFinalize.tsx1-329
Refresh this wiki