--- title: "Event handlers reference" description: "Complete reference for all FlowDrop event handlers." source: https://flowdrop.io/docs/editor/reference/event-handlers site: FlowDrop documentation --- # Event handlers reference FlowDrop exposes the same set of lifecycle callbacks through two surfaces: - **The `` component** takes them as **flat `on*` props** — `onBeforeSave`, `onAfterSave`, `onSaveError`, `onApiError`, `onWorkflowLoad`, `onBeforeSwap`, `onAfterSwap`. - **The mount options bag** (`mountFlowDropApp`, `mountWorkflowEditor`) takes the **grouped `eventHandlers` object**, which additionally wires `onWorkflowChange`, `onDirtyStateChange`, and `onBeforeUnmount`. ```typescript const app = await mountFlowDropApp(container, { eventHandlers: { /* handlers below */ } }); ``` Every handler is optional. ## Workflow lifecycle | Handler | Signature | When it fires | | -------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- | | `onWorkflowChange` | `(workflow: Workflow, changeType: WorkflowChangeType) => void` | Any modification to nodes, edges, config, or metadata | | `onWorkflowLoad` | `(workflow: Workflow) => void` | After a workflow is loaded and initialized | | `onDirtyStateChange` | `(isDirty: boolean) => void` | When the workflow transitions between saved and unsaved states | ### `WorkflowChangeType` values | Value | Trigger | | ------------- | --------------------------------- | | `node_add` | Node added to canvas | | `node_remove` | Node deleted | | `node_move` | Node dragged to new position | | `node_config` | Node configuration values changed | | `edge_add` | Connection drawn between nodes | | `edge_remove` | Connection deleted | | `metadata` | Workflow metadata changed | | `name` | Workflow name edited | | `description` | Workflow description edited | ## Save lifecycle | Handler | Signature | When it fires | | -------------- | ----------------------------------------------------- | -------------------------------------- | | `onBeforeSave` | `(workflow: Workflow) => Promise` | Before save. Return `false` to cancel. | | `onAfterSave` | `(workflow: Workflow) => Promise` | After successful save | | `onSaveError` | `(error: Error, workflow: Workflow) => Promise` | When save fails | ## Node swap | Handler | Signature | When it fires | | -------------- | ------------------------------------------------------------------------- | -------------------------------------- | | `onBeforeSwap` | `(context: SwapEventContext) => boolean \| void \| Promise` | Before a node swap. Return `false` to cancel. | | `onAfterSwap` | `(result: SwapResult, oldNode: WorkflowNode, newNodeId: string) => void` | After a node swap is applied | ## Error & cleanup | Handler | Signature | When it fires | | ----------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `onApiError` | `(error: Error, operation: string) => boolean \| void` | Any API request failure. Return `true` to suppress default toast. `operation` values: `"save"`, `"load"`, `"fetchNodes"`, `"fetchCategories"`, etc. | | `onBeforeUnmount` | `(workflow: Workflow, isDirty: boolean) => void` | Before FlowDrop is destroyed/unmounted | ## Agent Spec execution | Handler | Signature | When it fires | | ------------------------------- | ----------------------------------------------------------------- | ------------------------------------ | | `onAgentSpecExecutionStarted` | `(executionId: string) => void` | Execution begins | | `onAgentSpecExecutionCompleted` | `(executionId: string, results: Record) => void` | Execution succeeds | | `onAgentSpecExecutionFailed` | `(executionId: string, error: Error) => void` | Execution fails | | `onAgentSpecNodeStatusUpdate` | `(nodeId: string, status: NodeExecutionInfo) => void` | Node status changes during execution | ## Complete interface ```typescript interface FlowDropEventHandlers { onWorkflowChange?: (workflow: Workflow, changeType: WorkflowChangeType) => void; onDirtyStateChange?: (isDirty: boolean) => void; onBeforeSave?: (workflow: Workflow) => Promise; onAfterSave?: (workflow: Workflow) => Promise; onSaveError?: (error: Error, workflow: Workflow) => Promise; onWorkflowLoad?: (workflow: Workflow) => void; onBeforeUnmount?: (workflow: Workflow, isDirty: boolean) => void; onApiError?: (error: Error, operation: string) => boolean | void; onBeforeSwap?: (context: SwapEventContext) => boolean | void | Promise; onAfterSwap?: (result: SwapResult, oldNode: WorkflowNode, newNodeId: string) => void; onAgentSpecExecutionStarted?: (executionId: string) => void; onAgentSpecExecutionCompleted?: (executionId: string, results: Record) => void; onAgentSpecExecutionFailed?: (executionId: string, error: Error) => void; onAgentSpecNodeStatusUpdate?: (nodeId: string, status: NodeExecutionInfo) => void; } ``` For usage examples and patterns, see the [Event System guide](/editor/advanced/event-system).