npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@workflowbuilder/sdk

v2.2.0

Published

React SDK for Workflow Builder — embed a visual, flow-based workflow editor in your app.

Downloads

15,196

Readme

@workflowbuilder/sdk

React SDK for Workflow Builder. Embed a visual, flow-based workflow editor in your app.

npm version license

What you get

An embeddable React SDK that ships a complete workflow editor. One compound component (<WorkflowBuilder.Root>) is the embed point. Behind it: a plugin architecture, three persistence strategies, a JsonForms-driven schema layer, i18n, theming tokens, and a diagram-template system. You bring node types and a save strategy. The SDK handles canvas, palette, connections, properties, and persistence.

Typical fit:

  • Visual editors for AI agent workflows (LLM chains, tool calls, decision branches)
  • Drag-and-drop node-based programming UIs
  • ETL or data-pipeline designers
  • BPMN-style process editors
  • Any flow editor where you want JsonForms-driven node properties plus a swappable persistence layer

Battle-tested in production by teams shipping AI workflow products.

Install

npm install @workflowbuilder/sdk \
  react react-dom \
  @xyflow/react \
  @jsonforms/core @jsonforms/react \
  i18next react-i18next i18next-browser-languagedetector \
  immer zustand

The SDK ships its non-peer dependencies bundled in dist/. React, xyflow, JsonForms, i18next, immer, and zustand are declared as peerDependencies so your app and the SDK share a single copy of each. See Peer dependencies below.

Quick start

import { WorkflowBuilder } from '@workflowbuilder/sdk';

import '@workflowbuilder/sdk/style.css';

export function App() {
  return <WorkflowBuilder.Root name="my-workflow" />;
}

The editor renders with the default layout (top bar, palette, canvas, properties panel) and persists state to localStorage automatically (the default integration strategy). The palette is empty until you pass nodeTypes — see <Root> props, the Add a custom node type guide, and the node schemas reference for how to design the data and UI schemas.

Copy-paste-ready node implementations live in the source repo at apps/demo/src/app/data/nodes/. Each folder is a self-contained node type with 4 files (<name>.ts, default-properties-data.ts, schema.ts, uischema.ts). Available examples: trigger, action, decision, conditional, delay, notification, multi-port, ai-agent — each documented on the built-in nodes reference. Drop the folder into your app, import the node definition, and pass it to nodeTypes.

Compose a custom layout

Pass subcomponents as children to skip the default layout and place each part where you want it:

<WorkflowBuilder.Root nodeTypes={myNodeTypes}>
  <header>
    <WorkflowBuilder.TopBar />
  </header>
  <aside>
    <WorkflowBuilder.Palette />
  </aside>
  <main>
    <WorkflowBuilder.Canvas />
  </main>
  <aside>
    <WorkflowBuilder.PropertiesPanel />
  </aside>
</WorkflowBuilder.Root>

To add custom overlays alongside the default layout, mount it explicitly:

<WorkflowBuilder.Root nodeTypes={myNodeTypes}>
  <WorkflowBuilder.DefaultLayout />
  <MyToastBanner />
</WorkflowBuilder.Root>

Each subcomponent is also exported under a named alias (WorkflowBuilderTopBar, WorkflowBuilderPalette, WorkflowBuilderCanvas, WorkflowBuilderPropertiesPanel, WorkflowBuilderDefaultLayout) for consumers who prefer the classic style.

If you omit <WorkflowBuilder.TopBar />, use useWorkflowBuilderActions() to trigger save / import / export / settings / read-only / theme / layout-direction from your own controls.

<WorkflowBuilder.Root> props

| Prop | Type | Description | | ------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | nodeTypes | PaletteItemOrGroup[] | Node type definitions. Appear in the palette and drive validation. Must be a stable reference — declare at module scope or memoize. | | nodeTemplates | WorkflowBuilderNodeTemplates | Per-node-type custom renderers. Map of data.type → React component, overriding the default node renderer for that type. Stable reference required (same as nodeTypes). | | edgeTemplates | WorkflowBuilderEdgeTemplates | Per-edge-type custom renderers. Map of edge.type → React component taking ReactFlow EdgeProps, overriding the built-in labelEdge. Unregistered types fall back to the default edge. Stable reference required (same as nodeTypes). | | diagramTemplates | TemplateModel[] | Diagram templates available in the template selector. Stable reference required (same as nodeTypes). | | plugins | WorkflowBuilderPlugin[] | Functions registering decorators. Synchronous, executed once. | | jsonForm | WorkflowBuilderJsonFormConfig | Custom JsonForms renderers, cells, translations. | | integration | WorkflowBuilderIntegration | Data source / sink. Defaults to localStorage. | | name | string | Workflow name shown in the header. | | layoutDirection | 'DOWN' \| 'RIGHT' | Initial flow direction. | | initialNodes | WorkflowBuilderNode[] | Starting diagram nodes. | | initialEdges | WorkflowBuilderEdge[] | Starting diagram edges. | | isValidConnection | WorkflowBuilderIsValidConnection | Validate connections as the user draws them. See Connection validation. Stable reference required. | | reactFlowProps | WorkflowBuilderReactFlowProps | Advanced escape hatch for the underlying ReactFlow canvas. See Advanced: ReactFlow props. Treat as static config (runtime value changes may not apply immediately). | | children | ReactNode | Custom layout. Omit for the default floating-overlay layout (top bar, palette, canvas, properties panel). See Compose a custom layout. |

Exact prop types come from the auto-generated WorkflowBuilderRootProps reference. For how and when to reach for each prop, see Configuring the editor.

Persistence

Pick one of three strategies via the integration prop.

| Strategy | Source / sink | When to use | | -------------- | ----------------------------------------------------------- | ---------------------------- | | localStorage | Browser localStorage | Prototyping, quick starts | | api | GET / POST to user-provided endpoints | Backend-managed persistence | | props | onDataSave callback + initialNodes/initialEdges props | Host-app-managed persistence |

<WorkflowBuilder.Root
  integration={{
    strategy: 'api',
    endpoints: { load: '/api/load', save: '/api/save' },
  }}
/>

Full guide: Persistence strategies on the docs site.

Plugins

The SDK exposes three extension points. Pass plugin functions to the plugins prop:

  • Component decorators (registerComponentDecorator). Inject UI into named slots: OptionalAppBarControls, OptionalAppBarTools, OptionalAppChildren, OptionalEdgeProperties, OptionalFooterContent, OptionalHooks (invisible provider slot), OptionalNodeContent (receives nodeId).
  • Function decorators (registerFunctionDecorator). Observe or wrap SDK internals (e.g. trackFutureChange) before / after / wrapping the call.
  • Translations (registerPluginTranslation). Extend i18next keys with plugin-specific strings.
import { WorkflowBuilder, type WorkflowBuilderPlugin, registerComponentDecorator } from '@workflowbuilder/sdk';

import { MyToolbarButton } from './my-toolbar-button';

const myPlugin: WorkflowBuilderPlugin = () => {
  registerComponentDecorator('OptionalAppBarControls', {
    content: MyToolbarButton,
    name: 'MyPlugin',
  });
};

export function App() {
  return <WorkflowBuilder.Root plugins={[myPlugin]} />;
}

Plugins are synchronous. If you need async work (config fetch, WASM load, feature flag lookup), await it outside the SDK and construct the plugin around the resolved value before passing it to <Root>.

Full guide: Build a plugin.

Connection validation

isValidConnection decides whether a dragged connection is allowed. Return false to reject it: no edge is created, no flicker. It receives the resolved sourceNode / targetNode (plus the raw connection), so you branch on node data without reaching into the store.

import { WorkflowBuilder, type WorkflowBuilderIsValidConnection } from '@workflowbuilder/sdk';

// Module scope keeps the reference stable.
const isValidConnection: WorkflowBuilderIsValidConnection = ({ sourceNode, targetNode }) =>
  !(sourceNode.data.type === 'start' && targetNode.data.type === 'start');

export function App() {
  return <WorkflowBuilder.Root isValidConnection={isValidConnection} />;
}

Validates interactive drags only, not programmatic edge writes (templates, paste, setStoreEdges). Fail-open: if an endpoint can't be resolved to a node, the connection is allowed.

Advanced: ReactFlow props

reactFlowProps forwards extra props to the underlying ReactFlow canvas for things the SDK doesn't expose directly (zoom limits, key codes, onNodeClick, performance flags, …).

const reactFlowProps = {
  maxZoom: 1.5,
  zoomOnDoubleClick: false,
  onNodeClick: (_, node) => console.log(node.id),
} satisfies WorkflowBuilderReactFlowProps;

<WorkflowBuilder.Root reactFlowProps={reactFlowProps} />;

Props the SDK owns (graph data, the connection / selection / change handlers, type maps, colorMode, …) can't be set here. To observe SDK events use the listener APIs (addNodeChangedListener, …); to theme use Theming. Treat reactFlowProps as static config: runtime value changes may not apply immediately.

Theming

The editor exposes a small set of CSS custom properties for top-level styling. Override them on :root or scope to your app shell:

:root {
  --wb-background-color: #fafafa;
  --wb-font-family: 'Inter', system-ui, sans-serif;
  --wb-transition: 0.15s ease-in;
}

Available --wb-* tokens: --wb-background-color, --wb-font-family, --wb-transition, plus scrollbar styling (--wb-scroll-width, --wb-scroll-radius, --wb-scroll-thumb-color, --wb-scroll-thumb-hover-color, --wb-scroll-track-color).

Deeper color and spacing customization (palette, semantic UI tokens) goes through the --ax-* token layer from @synergycodes/overflow-ui. Full guide: Design system and customization.

CSS — global resets

@workflowbuilder/sdk/style.css contains a small set of global resets, including:

body {
  margin: 0;
  background-color: var(--wb-background-color);
  overflow: hidden;
}

html,
body,
#root {
  height: 100vh;
}

The rules ship inside @layer reset (the lowest precedence in the SDK's cascade layer order), so any consumer-level rule on body / html / #root wins automatically — no specificity hacks or !important needed. Two things to be aware of:

  • overflow: hidden on <body> — the editor expects a full-viewport canvas with no page-level scrollbar. If you embed the editor inside a scrolling page, override body { overflow: auto; } (or scope the SDK to a sized container with its own overflow: hidden) and let the editor's own viewport handle pan/zoom.
  • background-color: var(--wb-background-color) — the body picks up the SDK's background token. If you don't ship the SDK style sheet but render <WorkflowBuilder.Root />, the token is undefined and the body falls back to transparent. Either ship the CSS or set --wb-background-color yourself.

If you don't want the body resets at all, import the SDK before your own global stylesheet so your rules land in the unlayered cascade above @layer reset.

Single-instance constraint

Mount one <WorkflowBuilder.Root> per page. Plugin / JsonForms / i18n registries and the useStore.{getState,setState,subscribe} facade all share a module-level singleton, so two Roots on the same page would silently clash. If you need multiple "workflows" on one page, render them sequentially (mount → save → unmount → mount next).

TypeScript

dist/index.d.ts ships with all required types inlined: icon names (WBIcon), domain types (WorkflowBuilderNode, WorkflowBuilderEdge, NodeData, DiagramModel, PaletteItemOrGroup, TemplateModel, …), plugin contracts, and integration types. No extra @types/* package needed.

Full API reference: https://www.workflowbuilder.io/docs/api/core/workflowbuilder/.

Browser and runtime

  • Client-side only. The SDK holds module-level singletons (zustand store identity, i18next instance, immer's frozen-object cache) and uses i18next-browser-languagedetector. Mount inside 'use client' boundaries on Next.js, or behind a client-only wrapper (dynamic(() => import('./Editor'), { ssr: false })) on other SSR frameworks.
  • Modern browsers. Last two versions of Chrome, Firefox, Safari, Edge.
  • React 18 or 19.

Peer dependencies

Install alongside the SDK (ranges declared in peerDependencies):

  • react, react-dom (^18.0.0 || ^19.0.0)
  • @xyflow/react (^12.0.0)
  • @jsonforms/core, @jsonforms/react (^3.4.0)
  • i18next (^24.0.0), react-i18next (^15.0.0), i18next-browser-languagedetector (^8.0.0)
  • immer (^10.0.0)
  • zustand (^5.0.0)

These are declared as peerDependencies so the consumer app and the SDK share a single copy of each — required for singletons (zustand store identity, i18next instance, immer's frozen-object cache).

Support

Built and maintained by Synergy Codes - the engineers behind the SDK shipping workflow tools for 15 years across 20+ industries. Available for integration, customization, UX, back-end logic, and end-to-end delivery.

Talk to the team →

License

Apache 2.0 — see LICENSE.