--- title: "Mount API" description: "Complete reference for mountFlowDropApp(), mountWorkflowEditor(), and mountPlayground() — all options, return values, and lifecycle." source: https://flowdrop.io/docs/editor/reference/mount-api site: FlowDrop documentation --- # Mount API The mount API lets you embed FlowDrop into any HTML container, regardless of framework. ## `mountFlowDropApp()` Mounts the full FlowDrop application (sidebar, editor, config panel) into a container. ```typescript import { mountFlowDropApp } from '@flowdrop/flowdrop/editor'; const app = await mountFlowDropApp(container: HTMLElement, options: FlowDropMountOptions); ``` ### Options ```typescript interface FlowDropMountOptions { // Data /** Initial workflow to load */ workflow?: Workflow; /** Available node types (overrides API fetch) */ nodes?: NodeMetadata[]; // API /** REST API endpoint configuration */ endpointConfig?: EndpointConfig; /** Port data type configuration (overrides API fetch) */ portConfig?: PortConfig; /** Category definitions (overrides API fetch) */ categories?: CategoryDefinition[]; /** Authentication provider for API requests */ authProvider?: AuthProvider; // Event handlers — the grouped lifecycle events bag eventHandlers?: FlowDropEventHandlers; // Features features?: FlowDropFeatures; // UI options /** Show the top navbar @default true */ showNavbar?: boolean; /** Disable the node sidebar */ disableSidebar?: boolean; /** Editor interaction mode. @default 'edit' */ mode?: 'edit' | 'readonly' | 'locked'; /** Editor height (CSS value or number) */ height?: string | number; /** Editor width (CSS value or number) */ width?: string | number; // Navbar customization /** Custom navbar title */ navbarTitle?: string; /** Custom navbar action buttons */ navbarActions?: NavbarAction[]; /** Show settings gear icon in navbar */ showSettings?: boolean; /** Show the "Connected" status indicator in the navbar @default true */ showStatus?: boolean; // Pipeline mode /** Pipeline ID for execution status display */ pipelineId?: string; // Theme /** Visual theme — named built-in ('default' | 'minimal') or a custom theme object */ theme?: FlowDropTheme | FlowDropThemeName; // Instance /** Identifier for this instance. @default 'default' (auto-generated for extra mounts) */ instanceId?: string; // Settings /** Initial settings overrides (theme, behavior, editor, ui, api) */ settings?: PartialSettings; /** Custom localStorage key for draft auto-save */ draftStorageKey?: string; /** Where workflow drafts are persisted: 'local' (default), 'session', or a custom adapter */ draftStorage?: DraftStorageOption; /** Which settings tabs to show in the modal (defaults to all) */ settingsCategories?: SettingsCategory[]; /** Show the "Sync to Cloud" button in the settings modal */ showSettingsSyncButton?: boolean; /** Show the reset buttons in the settings modal */ showSettingsResetButton?: boolean; // Format adapters /** Custom workflow format adapters */ formatAdapters?: WorkflowFormatAdapter[]; /** Format ids this host supports — scopes the Workflow Format picker */ workflowFormats?: string[]; } ``` The `mode` option controls canvas interaction: `'edit'` (the default) allows editing; `'readonly'` and `'locked'` disable all canvas interaction. Use `workflowFormats` to scope the **Workflow Format** picker in the workflow settings panel to the formats your host can actually handle: ```typescript await mountFlowDropApp(container, { workflowFormats: ['flowdrop'] }); ``` When one or zero ids remain after filtering, the field is hidden instead of shown as a single-choice select, and the workflow keeps its stored format. Omit the option to offer every registered format. When you omit `instanceId`, the first mount on the page becomes the default instance (id `default`); additional mounts get auto-generated ids (`fd-1`, `fd-2`, …). Every instance scopes its draft and panel storage keys by id (`flowdrop:draft::…`). Pass an explicit `instanceId` whenever you mount more than one editor with drafts enabled, so the keys stay stable across page loads. ### Feature flags (`FlowDropFeatures`) ```typescript interface FlowDropFeatures { /** Auto-save the current workflow to localStorage as a draft. @default true */ autoSaveDraft?: boolean; /** How often to auto-save the draft, in milliseconds. @default 30000 */ autoSaveDraftInterval?: number; /** Show toast notifications for save success, failure, and API errors. * Disable if you want to handle notifications yourself via event handlers. @default true */ showToasts?: boolean; } ``` See [Auto-Save & Drafts](/tutorials/recipes/auto-save-and-drafts) for practical examples. See [Core Types](/editor/reference/types) for `FlowDropEventHandlers` and `FlowDropFeatures`. ### Return value ```typescript interface MountedFlowDropApp { /** This mount's state container — drive the editor programmatically. */ instance: FlowDropInstance; /** Destroy the editor and clean up resources */ destroy(): void; /** Check if there are unsaved changes */ isDirty(): boolean; /** Mark the workflow as saved (clears dirty state) */ markAsSaved(): void; /** Get the current workflow data */ getWorkflow(): Workflow | null; /** Trigger save operation */ save(): Promise; /** Trigger export (downloads JSON file) */ export(): void; /** Clear all workflow drafts from draft storage. Returns the number of entries removed. */ clearAllDrafts(): number; } ``` `instance` is the state container — workflow, history, playground, interrupts, categories, and the rest. Call into it to drive the editor programmatically, e.g. `app.instance.workflow.addNode(...)` or `app.instance.history.undo()`. **Call `clearAllDrafts()` on logout.** Otherwise drafts persist across user sessions on shared devices. It clears the configured draft storage (`localStorage` unless changed via the `draftStorage` option). ## `mountWorkflowEditor()` Mounts just the editor canvas — no navbar, no sidebar. Useful for embedding a minimal editor. ```typescript import { mountWorkflowEditor } from '@flowdrop/flowdrop/editor'; const editor = await mountWorkflowEditor(container, { workflow: myWorkflow, endpointConfig: createEndpointConfig('/api/flowdrop'), portConfig: myPortConfig, // optional, overrides API categories: myCategories, // optional, overrides API instanceId: 'editor-b' // optional — scope to a named instance for multi-editor pages }); ``` Returns the same `MountedFlowDropApp` interface as `mountFlowDropApp()`. `instanceId` follows the same default-instance semantics as `mountFlowDropApp()` above. ## `mountPlayground()` Mounts the interactive playground for workflow testing. ```typescript import { mountPlayground } from '@flowdrop/flowdrop/playground'; const playground = await mountPlayground(container, { workflowId: 'my-workflow-id', endpointConfig: createEndpointConfig('/api/flowdrop'), mode: 'standalone', // 'standalone' | 'embedded' | 'modal' config: { pollingInterval: 1500, shouldStopPolling: (status) => ['completed', 'failed'].includes(status), isTerminalStatus: (status) => ['completed', 'failed'].includes(status) }, onSessionStatusChange: (newStatus, previousStatus) => { console.log(`${previousStatus} -> ${newStatus}`); }, onClose: () => console.log('Playground closed'), // required for embedded/modal height: '600px', width: '100%', initialSessionId: 'resume-session-id', // optional instanceId: 'playground-b' // optional — scope to a named instance }); ``` `instanceId` follows the same default-instance semantics as `mountFlowDropApp()`. **Live polling is page-global.** Playground state (sessions, messages, interrupts) is isolated per instance, but only one playground can actively poll at a time. Drive a non-polling playground via `pushMessages()` instead. ### Playground return value ```typescript interface MountedPlayground { /** Destroy and clean up */ destroy(): void; /** Get the current session */ getCurrentSession(): PlaygroundSession | null; /** Get all sessions */ getSessions(): PlaygroundSession[]; /** Get message count in current session */ getMessageCount(): number; /** Check if currently executing */ isExecuting(): boolean; /** Stop polling for messages */ stopPolling(): void; /** Restart polling */ startPolling(): void; /** Push poll response data */ pushMessages(response: PlaygroundMessagesApiResponse): void; /** Reset playground state */ reset(): void; } ``` ## `unmountFlowDropApp()` / `unmountPlayground()` Clean up a mounted instance. Equivalent to calling `.destroy()` on the returned object. ```typescript import { unmountFlowDropApp } from '@flowdrop/flowdrop/editor'; unmountFlowDropApp(container); ``` ## Lifecycle 1. **Mount** — Call `mountFlowDropApp()` with a container element 2. **Interact** — Use the returned API to control the editor programmatically 3. **Destroy** — Call `.destroy()` or the unmount function to clean up Registration of custom nodes and fields can happen **before or after** mounting. The node and field registries are instance-scoped — resolve them via `getInstance()` inside the component tree, or the mount handle's `.instance` outside it. Each registry tracks a version counter that invalidates dependent reactive reads. When you register a node or field after mount, that counter bumps and the editor re-resolves, so late registrations take effect.