> ## Documentation Index
> Fetch the complete documentation index at: https://flowdrop.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Event handlers reference

> Complete reference for all FlowDrop event handlers.

FlowDrop exposes the same set of lifecycle callbacks through two surfaces:

* **The `<App>` 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 theme={null}
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<boolean \| void>`    | Before save. Return `false` to cancel. |
| `onAfterSave`  | `(workflow: Workflow) => Promise<void>`               | After successful save                  |
| `onSaveError`  | `(error: Error, workflow: Workflow) => Promise<void>` | When save fails                        |

## Node swap

| Handler        | Signature                                                                    | When it fires                                 |
| -------------- | ---------------------------------------------------------------------------- | --------------------------------------------- |
| `onBeforeSwap` | `(context: SwapEventContext) => boolean \| void \| Promise<boolean \| void>` | 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<string, unknown>) => 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 theme={null}
interface FlowDropEventHandlers {
  onWorkflowChange?: (workflow: Workflow, changeType: WorkflowChangeType) => void;
  onDirtyStateChange?: (isDirty: boolean) => void;
  onBeforeSave?: (workflow: Workflow) => Promise<boolean | void>;
  onAfterSave?: (workflow: Workflow) => Promise<void>;
  onSaveError?: (error: Error, workflow: Workflow) => Promise<void>;
  onWorkflowLoad?: (workflow: Workflow) => void;
  onBeforeUnmount?: (workflow: Workflow, isDirty: boolean) => void;
  onApiError?: (error: Error, operation: string) => boolean | void;
  onBeforeSwap?: (context: SwapEventContext) => boolean | void | Promise<boolean | void>;
  onAfterSwap?: (result: SwapResult, oldNode: WorkflowNode, newNodeId: string) => void;
  onAgentSpecExecutionStarted?: (executionId: string) => void;
  onAgentSpecExecutionCompleted?: (executionId: string, results: Record<string, unknown>) => void;
  onAgentSpecExecutionFailed?: (executionId: string, error: Error) => void;
  onAgentSpecNodeStatusUpdate?: (nodeId: string, status: NodeExecutionInfo) => void;
}
```

For usage examples and patterns, see the [Event System guide](/guides/advanced/event-system).
