Skip to main content
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.
import { mountFlowDropApp } from '@flowdrop/flowdrop/editor';

const app = await mountFlowDropApp(container: HTMLElement, options: FlowDropMountOptions);

Options

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[];
}
The mode option controls canvas interaction: 'edit' (the default) allows editing; 'readonly' and 'locked' disable all canvas interaction.
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:<id>:…).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)

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 for practical examples. See Core Types for FlowDropEventHandlers and FlowDropFeatures.

Return value

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<void>;

  /** 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.
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.
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

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.
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.