Menu

Action System

Relevant source files

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.


Purpose and Architecture

The Action System serves as a unified interface between user interactions (keyboard, toolbar clicks, menu selections) and state mutations. Each action encapsulates:

  1. Execution logic - How the action modifies elements/state
  2. UI representation - How the action appears in toolbars/menus
  3. Keyboard shortcuts - Key combinations that trigger the action
  4. History capture - Whether/when changes are recorded for undo/redo
  5. Visibility predicates - Conditions determining when actions are available

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


Action Registration and Structure

Action Definition Interface

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

Core Action Properties

PropertyTypePurpose
namestringUnique identifier used to reference the action
labelstring | functionDisplay text in UI (can be dynamic based on state)
performfunctionExecution logic returning { elements?, appState?, captureUpdate }
iconReactNode | functionIcon for toolbar/menu (can be state-dependent)
keyTestfunctionTests if keyboard event should trigger action
PanelComponentReact.ComponentOptional UI component for action configuration
trackEventobject | booleanAnalytics tracking configuration
predicatefunctionDetermines if action should be visible/enabled
viewModebooleanWhether action is available in view-only mode

Sources: packages/excalidraw/actions/actionProperties.tsx300-355 packages/excalidraw/actions/actionCanvas.tsx54-90

Example Action Registration

Sources: packages/excalidraw/actions/actionProperties.tsx300-355


Action Execution Flow

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

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


CaptureUpdateAction Behavior

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

Capture Modes

ModeUse CaseExample
IMMEDIATELYDiscrete, undoable operationsDelete element, change stroke width, finalize drawing
EVENTUALLYContinuous operations that should batchColor picker sliding, opacity dragging, intermediate zoom
NEVERTransient state that shouldn't be undoneOpening/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


Action Integration with UI

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

Action Rendering Flow

When renderAction(actionName) is called:

  1. Lookup: ActionManager retrieves action by name from registry

  2. Predicate Check: Evaluates action.predicate() to determine visibility

  3. Component Render: Calls action.PanelComponent with props:

    • elements: ExcalidrawElement[]
    • appState: AppState
    • updateData: (value) => void - Triggers action execution
    • app: AppClassProperties
    • data?: any - Optional additional data
  4. User Interaction: User modifies value in PanelComponent

  5. Execute: updateData calls ActionManager.executeAction(action, "ui")

Sources: packages/excalidraw/components/Actions.tsx130-307 packages/excalidraw/actions/actionProperties.tsx329-358

Conditional Action Visibility

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


Property Modification Actions

The most common action pattern involves modifying element properties. The system provides helper functions for this:

changeProperty Helper

This helper:

  1. Identifies selected elements (including bound text if specified)
  2. Applies callback transformation to selected elements only
  3. Returns new elements array with immutable updates

Sources: packages/excalidraw/actions/actionProperties.tsx151-172

getFormValue Helper

This helper determines what value to display in UI controls by:

  1. Checking editing text element first
  2. Computing common value across selected elements
  3. Falling back to default value if no common value exists

Sources: packages/excalidraw/actions/actionProperties.tsx174-212


Built-in Action Categories

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

Property Actions

Actions that modify visual properties of elements:

Action NamePurposeFile Location
changeStrokeColorModify element stroke coloractionProperties.tsx300-355
changeBackgroundColorModify element background coloractionProperties.tsx357-435
changeFillStyleChange fill pattern (solid/hachure/cross-hatch)actionProperties.tsx437-515
changeStrokeWidthModify stroke thicknessactionProperties.tsx517-573
changeSloppinessAdjust hand-drawn roughnessactionProperties.tsx575-629
changeStrokeStyleSet line style (solid/dashed/dotted)actionProperties.tsx631-684
changeOpacityModify element transparencyactionProperties.tsx686-708
changeFontSizeChange text sizeactionProperties.tsx710-788
changeFontFamilyChange text fontactionProperties.tsx848-1042

Sources: packages/excalidraw/actions/actionProperties.tsx300-1200

Element Lifecycle Actions

Actions that affect element existence and state:

ActionTriggerBehavior
actionFinalizeEscape, Enter, pointer upCompletes multi-point drawing, binds arrows, closes loops
actionDeleteSelectedDelete, BackspaceRemoves selected elements, handles bound text, updates frames
actionDuplicateSelectionCtrl+DCopies selected elements with offset positioning

Sources: packages/excalidraw/actions/actionFinalize.tsx49-329 packages/excalidraw/actions/actionDeleteSelected.tsx33-329 packages/excalidraw/actions/actionDuplicateSelection.tsx31-121

Canvas Actions

Actions that modify viewport and canvas-level state:

ActionShortcutPurpose
actionZoomInCtrl/Cmd++Increase zoom level by ZOOM_STEP (0.1)
actionZoomOutCtrl/Cmd+-Decrease zoom level by ZOOM_STEP
actionResetZoomCtrl/Cmd+0Reset zoom to 100%
actionZoomToFitShift+1Fit all elements in viewport (max 100% zoom)
actionZoomToFitSelectionShift+3Fit selected elements, zooming beyond 100%
actionToggleThemeAlt+Shift+DSwitch between light/dark themes
actionClearCanvas-Delete all elements and reset state
actionToggleEraserToolEActivate/deactivate eraser tool
actionToggleHandToolHActivate/deactivate hand/pan tool

Sources: packages/excalidraw/actions/actionCanvas.tsx133-603


Keyboard Shortcut Handling

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

keyTest Function Signature

Example Implementations

Simple Key Combination:

Multiple Key Codes:

State-Dependent:

Common Key Constants

Used from @excalidraw/common/constants.ts:

ConstantKeysUsage
KEYS.CTRL_OR_CMDCtrl (Win/Linux) or Cmd (Mac)Modifier for shortcuts
KEYS.ESCAPEEscapeCancel operations
KEYS.ENTEREnterFinalize operations
KEYS.DELETEDeleteDelete elements
KEYS.BACKSPACEBackspaceDelete 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


Advanced Action Patterns

State-Dependent Action Behavior

Actions can modify their behavior based on current state:

Sources: packages/excalidraw/actions/actionFinalize.tsx49-310

Async Operations in Actions

While perform is synchronous, actions can trigger async side effects:

Sources: packages/excalidraw/actions/actionProperties.tsx1016-1038

Compound Actions

Actions can coordinate multiple element mutations:

Sources: packages/excalidraw/actions/actionFlip.ts36-207


Action System Summary

The Action System provides:

  1. Unified Command Interface - All user operations flow through the same action pipeline
  2. Declarative Configuration - Actions specify what they do, not how UI renders them
  3. Flexible History Control - Fine-grained control over undo/redo through CaptureUpdateAction
  4. Multi-Context Triggering - Actions work from keyboard, toolbar, menus, and API calls
  5. Type-Safe State Management - TypeScript ensures action inputs/outputs match expected types

Key interfaces:

  • register() - Registers action definitions with ActionManager
  • perform() - Executes action logic and returns updates
  • renderAction() - Renders action UI component
  • CaptureUpdateAction - Controls history recording behavior

Sources: packages/excalidraw/actions/actionProperties.tsx1-1200 packages/excalidraw/actions/actionCanvas.tsx1-603 packages/excalidraw/actions/actionFinalize.tsx1-329