# Svelte Flow Documentation What is Svelte Flow? Svelte Flow is a library that allows you to create interactive, node-based user interfaces: flowcharts, diagrams, visual programming tools, and workflows inside your svelte applications. It supports theming, custom nodes and edges, a library of shadcn UI components, and offers a large collection of examples for rapid development. Developers can leverage the Svelte Flow Pro platform for advanced features like real-time collaboration, complex layouts, and enhanced performance, making it suitable for both simple and large-scale, production-ready visual applications. ## Learn ### Quickstart If you want to get up and running as soon as possible, you're in the right place! This page will take you from zero to a working Svelte Flow app in a few minutes. From there, you can take a deeper look at what Svelte Flow is all about, check out the examples, or dive into the API docs. #### Dependency Svelte Flow is published on npm as [`@xyflow/svelte`](https://npmjs.com/package/@xyflow/svelte). ```bash copy npm2yarn npm install @xyflow/svelte ``` #### Play online You can try Svelte Flow without setting anything up locally by checking out the starter projects we have on [Stackblitz](https://stackblitz.com): JS } /> TS } /> #### Vite template If you want to get started right away, you can use our [vite template](https://github.com/xyflow/vite-svelte-flow-template): ```bash copy npm2yarn npx degit xyflow/vite-svelte-flow-template app-name ``` #### Project Setup To get started locally, you should have a few things: * [Node.js](https://nodejs.org/en/) installed. * Either npm or another package manager like [yarn](https://yarnpkg.com/) or [pnpm](https://pnpm.io/). * Some knowledge of [Svelte](https://svelte.dev/). You don't need to be an expert, but you should be comfortable with the basics. First, spin up a new [Svelte](https://svelte.dev/) project however you like; we recommend using [Vite](https://vitejs.dev/) and [SvelteKit](https://svelte.dev/docs/kit/introduction) but the choice is yours. ```bash copy npm2yarn npx sv create my-svelte-flow-app ``` Then, navigate to your project directory and install the Svelte Flow package: ```bash copy npm2yarn npm install @xyflow/svelte ``` #### Creating your first flow The `@xyflow/svelte` package exports the `` component, which is the entrypoint for you flow. Importing the default styles and defining a handful of nodes and edges are all we need to get started! There are a few things to pay attention to here: * You must import the Svelte Flow stylesheet. * `` inherits the size of its parent. Wrap it in an element with dimensions. * Use [`$state.raw`](https://svelte.dev/docs/svelte/$state#$state.raw) instead of deeply reactive state for the `nodes` and `edges` for [performance reasons](https://github.com/sveltejs/svelte/issues/11851). ```svelte
``` ### Server Side Rendering ### Server side rendering, server side generation This is an advanced use case and assumes you are already familiar with SvelteFlow. If you're new to SvelteFlow, check out our [getting started guide](/learn/getting-started/key-concepts). In this guide, you'll learn how to configure SvelteFlow for server-side rendering, enabling you to: * Generate static HTML diagrams for documentation * Render SvelteFlow diagrams in non-JavaScript environments * Create dynamic Open Graph images for social media sharing (For client-side image generation, check out our [download image example](/examples/misc/download-image).) ##### Why Server-Side Rendering is Complex To understand why server-side rendering in Svelte Flow requires special configuration, let's look at what SvelteFlow typically handles on the client side: 1. **Node Dimension Calculation** * Nodes can contain any content, so their dimensions are determined by the browser's layout engine * This dynamic sizing isn't available during server-side rendering 2. **Handle Position Detection** * Edge connections require precise handle positions * These positions are calculated based on CSS layout, which isn't available on the server 3. **Container Size Adaptation** * SvelteFlow adapts to its container's dimensions * Server-side rendering needs explicit dimensions ##### Node Dimensions The most crucial aspect of server-side rendering is specifying node dimensions. On the client, SvelteFlow automatically measures nodes and stores dimensions in `measured.width` and `measured.height`. For server-side rendering, you must provide these dimensions explicitly using either: Node Dimension Options: 1. `width` and `height`: Static dimensions that won't change
2. `initialWidth` and `initialHeight`: Dynamic dimensions that may change after client-side hydration
```svelte ``` ##### Handle Positions To render edges on the server, you need to provide handle positions explicitly. On the client, SvelteFlow calculates these positions automatically, but for server-side rendering, you must specify them using the `handles` property: ```svelte ``` ##### Using `fitView` with Server-Side Rendering If you know your container's dimensions, you can use `fitView` during server-side rendering by providing the container's width and height: ```svelte ``` ##### Generating Static HTML To create static HTML output, you can use Svelte's server-side rendering capabilities. This generates an HTML string that you can use for static files or HTTP responses: ```svelte ``` ### Usage with TypeScript Svelte Flow is written in TypeScript because we value the additional safety barrier it provides. We export all the types you need for correctly typing data structures and functions you pass to the Svelte Flow component. We also provide a way to extend the types of nodes and edges. #### Basic Usage Let's start with the essential types needed for a basic implementation. While TypeScript can infer some types automatically, we'll define them explicitly for clarity. ```svelte ``` ##### Custom Nodes When working with [custom nodes](/learn/customization/custom-nodes), you can extend the base `Node` type to include your custom data. There are two main approaches: 1. For **multiple custom nodes**, specify a custom `Node` type as a generic to `NodeProps`: ```svelte
A special number: {data.number}
``` ⚠️ When defining node data separately, you must use `type` (interfaces won't work): ```ts type NumberNodeData = { number: number }; type NumberNodeType = Node; ``` 2. For **a single custom node** that renders different content based on the node type, use a union type: ```svelte
{#if data.type === 'number'}
A special number: {data.number}
{:else}
A special text: {data.text}
{/if}
``` ##### Custom Edges Similar to custom nodes, you can extend the base `Edge` type for [custom edges](/learn/customization/custom-edges): ```svelte ``` #### Advanced Usage In complex applications, you'll likely have multiple custom nodes and edges with different data structures. When using built-in functions and hooks, you'll need to properly [narrow down](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) the types to prevent runtime errors. ##### `Node` and `Edge` Type Unions Many functions, callbacks, and hooks (including the SvelteFlow component) expect `NodeType` or `EdgeType` generics. These are unions of all your custom node and edge types. As long as you've properly typed your data objects, you can use their exported types. If you're using any built-in nodes ('input', 'output', 'default') or edges ('straight', 'step', 'smoothstep', 'bezier'), include the `BuiltInNode` and `BuiltInEdge` types from `@xyflow/svelte` in your union type. ```svelte ``` ##### Hooks You can use these type unions to properly type the return values of hooks: ```svelte ``` ##### Type Guards TypeScript provides several ways to implement [type guards](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#typeof-type-guards). One common approach is to create type guard functions like `isNumberNode` or `isTextNode` to filter specific nodes from a list: ```ts function isNumberNode(node: NodeType): node is NumberNodeType { return node.type === 'number'; } // numberNodes is now correctly typed as NumberNodeType[] let numberNodes = $derived(nodes.filter(isNumberNode)); ``` ### Custom Edges Like [custom nodes](/learn/customization/custom-nodes), parts of a custom edge in Svelte Flow are just Svelte components: that means you can render anything you want along an edge! This guide shows you how to implement a custom edge with some additional controls. For a comprehensive reference of props available for custom edges, see the [`EdgeProps`](/api-reference/types/edge-props) documentation. #### A basic custom edge An edge isn't much use to us if it doesn't render a path between two connected nodes. These paths are always SVG-based and are typically rendered using the [``](/api-reference/components/base-edge) component. To calculate the actual SVG path to render, Svelte Flow comes with some handy utility functions: * [`getBezierPath`](/api-reference/utils/get-bezier-path) * [`getSmoothStepPath`](/api-reference/utils/get-smooth-step-path) * [`getStraightPath`](/api-reference/utils/get-straight-path) To kick start our custom edge, we'll just render a straight path between the source and target. ```svelte filename="CustomEdge.svelte" ``` All the props passed to your custom edge component can be found in the API reference under the [`EdgeProps`](/api-reference/types/edge-props) type. This gives us a straight edge that behaves the same as the default `"straight"` [edge type](/api-reference/types/edge#default-edge-types). To use it, we also need to update the [`edgeTypes`](/api-reference/svelte-flow#edge-types) prop on the `` component. It's important to define the `edgeTypes` object *outside of the component* or to use Svelte's `$derived` to prevent unnecessary re-renders. Svelte Flow will show a warning in the console if you forget to do this. ```svelte filename="App.svelte" ``` After defining the `edgeTypes` object, we can use our new custom edge by setting the `type` field of an edge to `"custom-edge"`. Example: guides/custom-edges ##### App.svelte ```svelte ``` ##### CustomEdge.svelte ```svelte ``` ##### index.css ```css html, body, #app { margin: 0; font-family: sans-serif; width: 100%; height: 100%; } /* This is just here to better match the design of svelteflow.dev */ .svelte-flow { --xy-background-color: #f7f9fb; --xy-edge-label-background-color-default: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Adding an edge label One of the more common uses for custom edges is rendering some controls or info along an edge's path. In Svelte Flow we call that an *edge label* and unlike the edge path, edge labels can be any Svelte component! Because Svelte Flows edges are mounted inside a SVG component, we need to escape it's context to render a custom edge label. For this, we have a handy [``](/api-reference/components/edge-label) component. Aside from a couple of extras, like inheriting the edges z-index, it functions as a portal that mounts the child components in the viewport div. Let's add a button to our custom edge that can be used to delete the edge it's attached to: ```svelte filename="CustomEdge.svelte" ``` To make sure our edge labels are interactive and not just for presentation, it is important to add the `nodrag` and `nopan` classes to the label to stop mouse events from controlling the canvas. Here's an interactive example with our updated custom edge. Clicking the delete button will remove that edge from the flow. Creating a new edge will use the custom node. Example: guides/custom-edges-button ##### App.svelte ```svelte ``` ##### CustomEdge.svelte ```svelte ``` ##### index.css ```css html, body, #app { margin: 0; font-family: sans-serif; width: 100%; height: 100%; } /* This is just here to better match the design of svelteflow.dev */ .svelte-flow { --xy-background-color: #f7f9fb; --xy-edge-label-background-color-default: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Making Custom SVG Edge Paths As discussed previously, if you want to make a custom edge in Svelte Flow, you have to use either of the four path creation functions discussed above (e.g [`getBezierPath`](/api-reference/utils/get-bezier-path)). However if you want to make some other path shape like a Sinusoidal edge or some other edge type then you will have to make the edge path yourself. The edge path we get from functions like [`getBezierPath`](/api-reference/utils/get-bezier-path) is just a path string which we pass into the `path` prop of the `` component. It contains the necessary information needed in order to draw that path, like where it should start from, where it should curve, where it should end, etc. A simple straight path string between two points `(x1, y1)` to `(x2, y2)` would look like: ```svelte M x1 y1 L x2 y2 ``` An SVG path is a concatenated list of commands like `M`, `L`, `Q`, etc, along with their values. Some of these commands are listed below, along with their supported values. * `M x1 y1` is the Move To command which moves the current point to the x1, y1 coordinate. * `L x1 y1` is the Line To command which draws a line from the current point to x1, y1 coordinate. * `Q x1 y1 x2 y2` is the Quadratic Bezier Curve command which draws a bezier curve from the current point to the x2, y2 coordinate. x1, y1 is the control point of the curve which determines the curviness of the curve. Whenever we want to start a path for our custom edge, we use the `M` command to move our current point to `sourceX, sourceY` which we get as props in the custom edge component. Then based on the shape we want, we will use other commands like `L`(to make lines), `Q`(to make curves) and then finally end our path at `targetX, targetY` which we get as props in the custom edge component. If you want to learn more about SVG paths, you can check out [SVG-Path-Editor](https://yqnn.github.io/svg-path-editor/). You can paste any SVG path there and analyze individual path commands via an intuitive UI. Here is an example with two types of custom edge paths, a Step edge and a Sinusoidal edge. You should look at the Step edge first to get your hands dirty with custom SVG paths since it's simple, and then look at how the Sinusoidal edge is made. After going through this example, you will have the necessary knowledge to make custom SVG paths for your custom edges. Example: guides/custom-edges-svg-path ##### App.svelte ```svelte ``` ##### SineEdge.svelte ```svelte ``` ##### StepEdge.svelte ```svelte ``` ##### index.css ```css html, body, #app { margin: 0; font-family: sans-serif; width: 100%; height: 100%; } /* This is just here to better match the design of svelteflow.dev */ .svelte-flow { --xy-background-color: #f7f9fb; --xy-edge-label-background-color-default: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ### Custom Nodes A powerful feature of Svelte Flow is the ability to create custom nodes. This gives you the flexibility to render anything you want within your nodes. We generally recommend creating your own custom nodes rather than relying on built-in ones. With custom nodes, you can add as many source and target handles as you like—or even embed form inputs, charts, and other interactive elements. In this section, we'll walk through creating a custom node featuring an input field that updates text elsewhere in your application. For further examples, we recommend checking out our [Custom Node Example](/examples/nodes/custom-node). #### Creating a Custom Node To create a custom node, all you need to do is create a Svelte component. Svelte Flow will automatically wrap it in an interactive container that injects essential props like the node's id, position, and data, and provides functionality for selection, dragging, and connecting handles. For a full reference on all available custom node props, take a look at the [Node Props](/api-reference/types/node-props). Let's dive into an example by creating a custom node called `TextUpdaterNode`. For this, we've added a controlled input field with a oninput handler. We simply use the 'text' property from the node's data for the input and we update the node's data via the [`updateNodeData`](/api-reference/hooks/use-svelte-flow#update-node-data) function, that can be accessed through the [`useSvelteFlow`](/api-reference/hooks/use-svelte-flow) hook. ```svelte filename="TextUpdaterNode.svelte"
{ updateNodeData(id, { text: evt.target.value }); }} class="nodrag" />
``` #### Adding the Node Type Now we need to communicate the new custom node to Svelte Flow. You can add custom nodes by passing the [`nodeTypes`](/api-reference/svelte-flow#node-types) prop. ```svelte filename="App.svelte" ``` After defining your new node type, you can refer to it by using the `type` node option: ```js let nodes = $state.raw([ { id: 'node-1', type: 'textUpdater', position: { x: 0, y: 0 }, data: { text: 'some text' }, }, ]); ``` After putting it all together and adding some basic styles we get a custom node that prints text to the console: Example: guides/custom-nodes ##### App.svelte ```svelte ``` ##### TextUpdaterNode.svelte ```svelte
{ updateNodeData(id, { text: evt.target.value }); }} class="nodrag" />
``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } #app { width: 100vw; height: 100vh; } .svelte-flow { --xy-background-color: #f7f9fb; } .text-updater-node { height: 50px; border: 1px solid #eee; padding: 5px; border-radius: 5px; background: white; } .text-updater-node label { display: block; color: #777; font-size: 12px; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Adding Handles Svelte Flow provides a [`Handle`](/api-reference/components/handle) component that can be used to add handles to your custom nodes. It's as easy as mounting the component. ```svelte filename="CustomNode.svelte" highlight="Handle" ``` ###### Multiple Handles If you need more than just one source and target handle, you can use the `id` ### Theming Svelte Flow comes with minimal default styles and was designed to be fully customizable. Many of our users fully transform the look and feel of Svelte Flow to match their own brand or design system. This guide will introduce you to the different ways you can customize Svelte Flow's appearance. #### Default styles Svelte Flow's default styles are enough to get going with the built-in nodes. They provide some sensible defaults for styles like padding, border radius, and animated edges. You can see what they look like below: ```js import '@xyflow/svelte/dist/style.css'; ``` Example: guides/theming/a ##### App.svelte ```svelte ``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } #app { width: 100vw; height: 100vh; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Base styles If you just want to load the very basic styles that are necessary for Svelte Flow to work, you can import the base styles instead: ```js import '@xyflow/svelte/dist/base.css'; ``` These base styles are **required** for Svelte Flow to function correctly. If you don't expected! Example: guides/theming/b ##### App.svelte ```svelte ``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } #app { width: 100vw; height: 100vh; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Customization There are different ways how you can customize the appearance of Svelte Flow: * Work with scoped CSS within your custom nodes and edges * Override the built-in classes with custom CSS * Override the CSS variables Svelte Flow uses * Pass inline styles through `style` props ##### Working with built-in classes If you want to override the default styles, you can do so by overriding the built-in CSS classes. You can find a list of all the classes used by Svelte Flow below: | Class name | Description | | :---------------------------------- | :--------------------------------------------------------------------------------------- | | `.svelte-flow` | The outermost container | | `.svelte-flow__renderer` | The inner container | | `.svelte-flow__zoompane` | Zoom & pan pane | | `.svelte-flow__selectionpane` | Selection pane | | `.svelte-flow__selection` | User selection | | `.svelte-flow__edges` | The element containing all edges in the flow | | `.svelte-flow__edge` | Applied to each [`Edge`](/api-reference/types/edge) in the flow | | `.svelte-flow__edge.selected` | Added to an [`Edge`](/api-reference/types/edge) when selected | | `.svelte-flow__edge.animated` | Added to an [`Edge`](/api-reference/types/edge) when its `animated` prop is `true` | | `.svelte-flow__edge-path` | The SVG `` element of an [`Edge`](/api-reference/types/edge) | | `.svelte-flow__edge-label` | The edge label | | `.svelte-flow__connection` | Applied to the current connection line | | `.svelte-flow__connection-path` | The SVG `` of a connection line | | `.svelte-flow__nodes` | The element containing all nodes in the flow | | `.svelte-flow__node` | Applied to each [`Node`](/api-reference/types/node) in the flow | | `.svelte-flow__node.selected` | Added to a [`Node`](/api-reference/types/node) when selected. | | `.svelte-flow__node-default` | Added when [`Node`](/api-reference/types/node) type is `"default"` | | `.svelte-flow__node-input` | Added when [`Node`](/api-reference/types/node) type is `"input"` | | `.svelte-flow__node-output` | Added when [`Node`](/api-reference/types/node) type is `"output"` | | `.svelte-flow__node-group` | Added when [`Node`](/api-reference/types/node) type is `"group"` | | `.svelte-flow__nodesselection` | Nodes selection | | `.svelte-flow__nodesselection-rect` | Nodes selection rect | | `.svelte-flow__handle` | Applied to each [``](/api-reference/components/handle) component | | `.svelte-flow__handle-top` | Applied when a handle's [`Position`](/api-reference/types/position) is set to `"top"` | | `.svelte-flow__handle-right` | Applied when a handle's [`Position`](/api-reference/types/position) is set to `"right"` | | `.svelte-flow__handle-bottom` | Applied when a handle's [`Position`](/api-reference/types/position) is set to `"bottom"` | | `.svelte-flow__handle-left` | Applied when a handle's [`Position`](/api-reference/types/position) is set to `"left"` | | `.svelte-flow__handle.connecting` | Applied when a connection line is above a handle. | | `.svelte-flow__handle.valid` | Applied when a connection line is above a handle **and** the connection is valid | | `.svelte-flow__background` | Applied to the [``](/api-reference/components/background) component | | `.svelte-flow__minimap` | Applied to the [``](/api-reference/components/mini-map) component | | `.svelte-flow__controls` | Applied to the [``](/api-reference/components/controls) component | Be careful if you go poking around the source code looking for other classes to override. Some classes are used internally and are required in order for the library to be functional. If you replace them you may end up with unexpected bugs or errors! ##### CSS variables If you don't want to replace the default styles entirely but just want to tweak the overall look and feel, you can override some of the CSS variables we use throughout the library. These variables are mostly self-explanatory. Below is a table of all the variables you might want to tweak and their default values for reference: | Variable name | Default | | :---------------------------------------------------- | :---------------------------------- | | `--xy-edge-stroke-default` | `#b1b1b7` | | `--xy-edge-stroke-width-default` | `1` | | `--xy-edge-stroke-selected-default` | `#555` | | `--xy-connectionline-stroke-default` | `#b1b1b7` | | `--xy-connectionline-stroke-width-default` | `1` | | `--xy-attribution-background-color-default` | `rgba(255, 255, 255, 0.5)` | | `--xy-minimap-background-color-default` | `#fff` | | `--xy-background-pattern-dot-color-default` | `#91919a` | | `--xy-background-pattern-line-color-default` | `#eee` | | `--xy-background-pattern-cross-color-default` | `#e2e2e2` | | `--xy-node-color-default` | `inherit` | | `--xy-node-border-default` | `1px solid #1a192b` | | `--xy-node-background-color-default` | `#fff` | | `--xy-node-group-background-color-default` | `rgba(240, 240, 240, 0.25)` | | `--xy-node-boxshadow-hover-default` | `0 1px 4px 1px rgba(0, 0, 0, 0.08)` | | `--xy-node-boxshadow-selected-default` | `0 0 0 0.5px #1a192b` | | `--xy-handle-background-color-default` | `#1a192b` | | `--xy-handle-border-color-default` | `#fff` | | `--xy-selection-background-color-default` | `rgba(0, 89, 220, 0.08)` | | `--xy-selection-border-default` | `1px dotted rgba(0, 89, 220, 0.8)` | | `--xy-controls-button-background-color-default` | `#fefefe` | | `--xy-controls-button-background-color-hover-default` | `#f4f4f4` | | `--xy-controls-button-color-default` | `inherit` | | `--xy-controls-button-color-hover-default` | `inherit` | | `--xy-controls-button-border-color-default` | `#eee` | | `--xy-controls-box-shadow-default` | `0 0 2px 1px rgba(0, 0, 0, 0.08)` | These variables are used to define the *defaults* for the various elements of Svelte Flow. This means they can still be overridden by inline styles or custom classes on a per-element basis. If you want to override a variable, you can do so by adding: ```css .svelte-flow { --xy-node-background-color-default: #ff5050; } ``` ##### Tailwind Custom nodes and edges are just Svelte components, and you can use any styling solution you'd like to style them. For example, you might want to use [Tailwind](https://tailwindcss.com/) to style your nodes: ```svelte
{data.emoji}
{data.name}
{data.job}
``` If you want to overwrite default styles, make sure to import Tailwinds entry last! ```js import '@xyflow/svelte/dist/style.css'; import 'tailwind.css'; ``` For a complete example of using Tailwind with Svelte Flow, check out the [tailwind example](/examples/styling/tailwind)! ### Building a Flow Ready to create your first flow? This guide will walk you through the process step by step. If you haven't reviewed our [Key Concepts](/learn/getting-started/key-concepts) yet, we recommend doing that first. #### Getting Started First, import the Svelte Flow Component and its required styles into your project. We'll also import the `Background` component for visual enhancement. ```svelte ``` Next, render the main component inside an element with defined dimensions and place the `Background` component inside `SvelteFlow`. Content inside `SvelteFlow` stays fixed on top of the viewport. The `Background` component transforms its pattern to match viewport movement. ```svelte
``` If everything is set up correctly, you should see a blank canvas like this: Example: guides/getting-started/a ##### App.svelte ```svelte
``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Adding nodes Now that the flow is set up, let's add some nodes. Create an array of [node objects](/api-reference/types/node) with these **required** properties: * `id`: A unique identifier for each node * `position`: The x and y coordinates * `data`: An object for storing custom data We'll use the [`$state.raw`](https://svelte.dev/docs/svelte/$state) rune to make the array reactive. Simply using `$state` would **not only** make the array reactive, but **every property of each node**, too. This could lead to [performance issues](https://github.com/sveltejs/svelte/issues/11851), so we use [`$state.raw`](https://svelte.dev/docs/svelte/$state#$state.raw) instead. ```js let nodes = $state.raw([ { id: '1', position: { x: 0, y: 0 }, data: { label: 'Hello' }, }, { id: '2', position: { x: 100, y: 100 }, data: { label: 'World' }, }, ]); ``` Next, we [bind](https://svelte.dev/docs/svelte/$bindable) the nodes to the `SvelteFlow` component. This two-way binding allows both the component and your code to modify the nodes. ```svelte ``` If you've followed these steps, you should see a flow that looks like this: Example: guides/getting-started/b ##### App.svelte ```svelte
``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Adding edges Let's connect the nodes with an edge. Initialize a [`$state.raw`](https://svelte.dev/docs/svelte/$state#$state.raw) with an array of [edge objects](/api-reference/types/edge) that have these **required** properties: * `id`: A unique identifier for the edge * `source`: The ID of the source node * `target`: The ID of the target node ```js let edges = $state.raw([{ id: 'e1-2', source: '1', target: '2' }]); ``` As with nodes, we [bind](https://svelte.dev/docs/svelte/$bindable) the edges to the `SvelteFlow` component. ```svelte ``` Your flow should now look like this: Example: guides/getting-started/c ##### App.svelte ```svelte
``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Polishing the flow This all might already go into the right drection but it still looks a little bland and lopsided, doesn't it? ###### `fitView` Add the [`fitView`](/api-reference/svelte-flow#fitview) prop to automatically fit the initial viewport to the visible nodes. ```svelte ``` ###### Built-in node types Let's change the `type` of the first node to `input` and the second node to `output`. These are built-in node types, that come with a different set of handles. ```js let nodes = $state.raw([ { id: '1', type: 'input', position: { x: 0, y: 0 }, data: { label: 'Hello' }, }, { id: '2', type: 'output', position: { x: 100, y: 100 }, data: { label: 'World' }, }, ]); ``` ###### Built-in edge types We change the edge to type `smoothstep` and also give it a label! ```js let edges = $state.raw([ { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', label: 'to the' }, ]); ``` #### Finished Flow And there you have it! Your completed flow should look like this: Example: guides/getting-started/d ##### App.svelte ```svelte
``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } /* This is just here to better match the design of svelteflow.dev */ .svelte-flow { --xy-background-color: #f7f9fb; --xy-edge-label-background-color-default: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ### Built-In Components Svelte Flow comes with several additional components that you can plug into your flow. All you have to do is import and add them as children to the `SvelteFlow` component. ```svelte filename="BuiltInComponents.svelte"

My Flow

``` #### MiniMap The [`MiniMap`](/api-reference/components/mini-map) provides a bird's-eye view of your flowgraph, making navigation easier, especially for larger flows. You can customize the appearance of nodes in the minimap by providing a `nodeColor` function. Example: guides/built-in-components/minimap ##### App.svelte ```svelte { switch (node.type) { case 'input': return '#6ede87'; case 'output': return '#6865A5'; default: return '#ff0072'; } }} zoomable pannable /> ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } ``` ##### index.html ```html SvelteFlow MiniMap Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Controls Svelte Flow comes with a set of customizable [`Controls`](/api-reference/components/controls) for the viewport. You can zoom in and out, fit the viewport and toggle if the user can move, select and edit the nodes. Example: guides/built-in-components/controls ##### App.svelte ```svelte ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html SvelteFlow Controls Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Background The [`Background`](/api-reference/components/background) component adds a visual grid pattern to your flowgraph, helping users maintain orientation. You can choose from different pattern variants, or if you need more advanced customization, you can explore the [source code](https://github.com/xyflow/xyflow/blob/main/packages/svelte/src/lib/plugins/Background/Background.svelte) to implement your own pattern. Example: guides/built-in-components/background ##### App.svelte ```svelte
variant:
``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html SvelteFlow Background Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` #### Panel The [`Panel`](/api-reference/components/panel) component allows you to add fixed overlays to your flowgraph, perfect for titles, controls, or any other UI elements that should remain stationary. Example: guides/built-in-components/panel ##### App.svelte ```svelte top-left top-center top-right bottom-left bottom-center bottom-right center-left center-right ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } .svelte-flow { --xy-background-color: #f7f9fb; } .svelte-flow__panel { padding: 5px 10px; background: white; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; } ``` ##### index.html ```html SvelteFlow Panel Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ### Installation and Requirements For this set-up we assume you already have node.js and npm, yarn or pnpm already installed. The Svelte Flow package is published under [`@xyflow/svelte`](https://www.npmjs.com/package/@xyflow/svelte) on npm and installable via: ```bash copy npm2yarn npm install @xyflow/svelte ``` Now you can import the Svelte Flow component and the styles in your application: ```js import { SvelteFlow } from '@xyflow/svelte'; import '@xyflow/svelte/dist/style.css'; ``` #### Hit the ground running To get folks building quickly, we have a template repository on GitHub that uses Vite and Svelte. You can find the template [here](https://github.com/xyflow/vite-svelte-flow-template). To use it, you can either create a new repository from the template, or use `degit` to grab the template's files without the git history: ```bash copy npx degit xyflow/vite-svelte-flow-template your-app-name ``` #### Prior Experience Needed Svelte Flow is a Svelte library. That means Svelte developers will feel comfortable using it. If basic Svelte terms and concepts like reactive state, props, components, and lifecycle methods are unfamiliar to you, you might need to learn more about Svelte before being able to use Svelte Flow fully. If you've never used Svelte before, we recommend first getting started on Svelte through the [official tutorial](https://svelte.dev/tutorial/svelte/welcome-to-svelte). ### Key Concepts At its core, Svelte Flow is about creating interactive flowgraphs - a collection of nodes connected by edges. While this might sound simple in theory, Svelte Flow provides the foundation for building complex interactive diagrams: * An infinite, interactive canvas for your flowgraph * The ability to render and connect nodes with edges * **Everything is built using standard Svelte components** To help you understand the terminology we use throughout the documentation, take a look at the example flow below. \[Example not found: /guides/concepts/] Here are the key terms you'll encounter when working with Svelte Flow: * **Svelte Flow Component**: The main component that renders your flowgraph * [**Svelte Flow Props**](/api-reference/svelte-flow): All configuration and data is passed through props * **Viewport**: The visible area of your flowgraph that can be panned and zoomed * When we say something is "in the viewport," it means it moves with the viewport's transformation * [**Base Styles**](/learn/customization/theming): The essential CSS required for Svelte Flow to function properly * [**Built-In Components**](/learn/getting-started/built-in-components): Ready-to-use components like Controls and MiniMap that enhance your flowgraph With these concepts in mind, you're ready to [install Svelte Flow](/learn/getting-started/installation) and start [building your first flow](/learn/getting-started/building-a-flow)! ### Layouting We regularly get asked how to handle layouting in Svelte Flow. While we could build some basic layouting into Svelte Flow, we believe that **you know your app's requirements best** and with so many options out there we think it's better you choose the best right tool for the job (not to mention it'd be a whole bunch of work for us). That doesn't help very much if you don't know what the options *are*, so this guide is here to help! We'll split things up into resources for layouting nodes and resources for routing edges. To start, let's explore several different layouting libraries and how they can be used with Svelte Flow. #### Layouting Nodes For layouting nodes, there are a few third-party libraries that we think are worth checking out: | Library | Dynamic node sizes | Sub-flow layouting | Edge routing | Bundle size | | -------------------------------------------------- | ------------------ | ------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | [Dagre](https://github.com/dagrejs/dagre) | Yes | Yes¹ | No | | | [D3-Hierarchy](https://github.com/d3/d3-hierarchy) | No | No | No | | | [D3-Force](https://github.com/d3/d3-force) | Yes | No | No | | | [ELK](https://github.com/kieler/elkjs) | Yes | Yes | Yes | | ¹ Dagre currently has an [open issue](https://github.com/dagrejs/dagre/issues/238) that prevents it from laying out sub-flows correctly if any nodes in the sub-flow are connected to nodes outside the sub-flow. We've loosely ordered these options from simplest to most complex, where dagre is largely a drop-in solution and elkjs is a full-blown highly configurable layouting engine. Below, we'll take a look at a brief example of how each of these libraries can be used with Svelte Flow. For dagre and elkjs specifically, we have some separate examples you can refer back to [here](/examples/layout/dagre) and [here](/examples/layout/elkjs). ##### Dagre * Repo: * Docs: Dagre is a simple library for layouting directed graphs. It has minimal configuration options and a focus on speed over choosing the most optimal layout. If you need to organize your flows into a tree, *we highly recommend dagre*. Example: guides/layouting/dagre ##### App.svelte ```svelte ``` ##### Flow\.svelte ```svelte ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } ``` ##### index.html ```html SvelteFlow Dagre Layout Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### nodes-edges.js ```js export const initialNodes = [ { id: '1', type: 'input', data: { label: 'input' }, position: { x: 0, y: 0 }, }, { id: '2', data: { label: 'node 2' }, position: { x: 0, y: 100 }, }, { id: '2a', data: { label: 'node 2a' }, position: { x: 0, y: 200 }, }, { id: '2b', data: { label: 'node 2b' }, position: { x: 0, y: 300 }, }, { id: '2c', data: { label: 'node 2c' }, position: { x: 0, y: 400 }, }, { id: '2d', data: { label: 'node 2d' }, position: { x: 0, y: 500 }, }, { id: '3', data: { label: 'node 3' }, position: { x: 200, y: 100 }, }, ]; export const initialEdges = [ { id: 'e12', source: '1', target: '2', animated: true }, { id: 'e13', source: '1', target: '3', animated: true }, { id: 'e22a', source: '2', target: '2a', animated: true }, { id: 'e22b', source: '2', target: '2b', animated: true }, { id: 'e22c', source: '2', target: '2c', animated: true }, { id: 'e2c2d', source: '2c', target: '2d', animated: true }, ]; ``` With no effort at all we get a well-organized tree layout! Whenever `getLayoutedElements` is called, we'll reset the dagre graph and set the graph's direction (either left-to-right or top-to-bottom) based on the `direction` prop. Dagre needs to know the dimensions of each node in order to lay them out, so we iterate over our list of nodes and add them to dagre's internal graph. After laying out the graph, we'll return an object with the layouted nodes and edges. We do this by mapping over the original list of nodes and updating each node's position according to node stored in the dagre graph. Documentation for dagre's configuration options can be found [here](https://github.com/dagrejs/dagre/wiki#configuring-the-layout), including properties to set for spacing and alignment. ##### D3-Hierarchy * Repo: * Docs: When you know your graph is a tree with a single root node, d3-hierarchy can provide a handful of interesting layouting options. While the library can layout a simple tree just fine, it also has layouting algorithms for tree maps, partition layouts, and enclosure diagrams. Example: guides/layouting/d3 ##### App.svelte ```svelte ``` ##### Flow\.svelte ```svelte ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } ``` ##### index.html ```html SvelteFlow MiniMap Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### nodes-edges.js ```js export const initialNodes = [ { id: '1', type: 'input', data: { label: 'input' }, position: { x: 0, y: 0 }, }, { id: '2', data: { label: 'node 2' }, position: { x: 0, y: 100 }, }, { id: '2a', data: { label: 'node 2a' }, position: { x: 0, y: 200 }, }, { id: '2b', data: { label: 'node 2b' }, position: { x: 0, y: 300 }, }, { id: '2c', data: { label: 'node 2c' }, position: { x: 0, y: 400 }, }, { id: '2d', data: { label: 'node 2d' }, position: { x: 0, y: 500 }, }, { id: '3', data: { label: 'node 3' }, position: { x: 200, y: 100 }, }, ]; export const initialEdges = [ { id: 'e12', source: '1', target: '2', animated: true }, { id: 'e13', source: '1', target: '3', animated: true }, { id: 'e22a', source: '2', target: '2a', animated: true }, { id: 'e22b', source: '2', target: '2b', animated: true }, { id: 'e22c', source: '2', target: '2c', animated: true }, { id: 'e2c2d', source: '2c', target: '2d', animated: true }, ]; ``` D3-hierarchy expects your graphs to have a single root node, so it won't work in all cases. It's also important to note that d3-hierarchy assigns the same width and height to _all_ nodes when calculating the layout, so it's not the best choice if you're displaying lots of different node types. ##### D3-Force * Repo: * Docs: For something more interesting than a tree, a force-directed layout might be the way to go. D3-Force is a physics-based layouting library that can be used to position nodes by applying different forces to them. As a consequence, it's a little more complicated to configure and use compared to dagre and d3-hierarchy. Importantly, d3-force's layouting algorithm is iterative, so we need a way to keep computing the layout across multiple renders. First, let's see what it does: Example: guides/layouting/d3-force ##### App.svelte ```svelte ``` ##### Flow\.svelte ```svelte ``` ##### collide.js ```js import { quadtree } from 'd3-quadtree'; export function collide() { let nodes = []; let force = (alpha) => { const tree = quadtree( nodes, (d) => d.x, (d) => d.y, ); for (const node of nodes) { const r = node.measured.width / 2; const nx1 = node.x - r; const nx2 = node.x + r; const ny1 = node.y - r; const ny2 = node.y + r; tree.visit((quad, x1, y1, x2, y2) => { if (!quad.length) { do { if (quad.data !== node) { const r = node.measured.width / 2 + quad.data.width / 2; let x = node.x - quad.data.x; let y = node.y - quad.data.y; let l = Math.hypot(x, y); if (l < r) { l = ((l - r) / l) * alpha; node.x -= x *= l; node.y -= y *= l; quad.data.x += x; quad.data.y += y; } } } while ((quad = quad.next)); } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }); } }; force.initialize = (newNodes) => (nodes = newNodes); return force; } export default collide; ``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } ``` ##### index.html ```html SvelteFlow MiniMap Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### nodes-edges.js ```js export const initialNodes = [ { id: '1', type: 'input', data: { label: 'input' }, position: { x: 0, y: 0 }, }, { id: '2', data: { label: 'node 2' }, position: { x: 0, y: 100 }, }, { id: '2a', data: { label: 'node 2a' }, position: { x: 0, y: 200 }, }, { id: '2b', data: { label: 'node 2b' }, position: { x: 0, y: 300 }, }, { id: '2c', data: { label: 'node 2c' }, position: { x: 0, y: 400 }, }, { id: '2d', data: { label: 'node 2d' }, position: { x: 0, y: 500 }, }, { id: '3', data: { label: 'node 3' }, position: { x: 200, y: 100 }, }, ]; export const initialEdges = [ { id: 'e12', source: '1', target: '2', animated: true }, { id: 'e13', source: '1', target: '3', animated: true }, { id: 'e22a', source: '2', target: '2a', animated: true }, { id: 'e22b', source: '2', target: '2b', animated: true }, { id: 'e22c', source: '2', target: '2c', animated: true }, { id: 'e2c2d', source: '2c', target: '2d', animated: true }, ]; ``` In our Svelte implementation, we use Svelte's lifecycle hooks and reactive state to manage the force simulation. The simulation is configured with a number of different forces applied so you can see how they interact: play around in your own code to see how you want to configure those forces. You can find the documentation and some different examples of d3-force [here](https://d3js.org/d3-force). Rectangular collisions D3-Force has a built-in collision force, but it assumes nodes are circles. We've thrown together a custom force in `collision.js` that uses a similar algorithm but accounts for our rectangular nodes instead. Feel free to steal it or let us know if you have any suggestions for improvements! The tick function progresses the simulation by one step and then updates Svelte Flow with the new node positions. We've also included a demonstration on how to handle node dragging while the simulation is running: if your flow isn't interactive you can ignore that part! For larger graphs, computing the force layout every render forever is going to incur a big performance hit. In this example we have a simple toggle to turn the layouting on and off, but you might want to come up with some other approach to only compute the layout when necessary. ##### Elkjs * Repo: * Docs: (good luck!) Elkjs is certainly the most configurable option available, but it's also the most complicated. Elkjs is a Java library that's been ported to JavaScript, and it provides a huge number of options for configuring the layout of your graph. Example: guides/layouting/elkjs ##### App.svelte ```svelte ``` ##### Flow\.svelte ```svelte
``` ##### index.css ```css html, body, #app { width: 100%; height: 100%; margin: 0; font-family: sans-serif; } ``` ##### index.html ```html SvelteFlow MiniMap Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### nodes-edges.js ```js export const initialNodes = [ { id: '1', type: 'input', data: { label: 'input' }, position: { x: 0, y: 0 }, }, { id: '2', data: { label: 'node 2' }, position: { x: 0, y: 100 }, }, { id: '2a', data: { label: 'node 2a' }, position: { x: 0, y: 200 }, }, { id: '2b', data: { label: 'node 2b' }, position: { x: 0, y: 300 }, }, { id: '2c', data: { label: 'node 2c' }, position: { x: 0, y: 400 }, }, { id: '2d', data: { label: 'node 2d' }, position: { x: 0, y: 500 }, }, { id: '3', data: { label: 'node 3' }, position: { x: 200, y: 100 }, }, ]; export const initialEdges = [ { id: 'e12', source: '1', target: '2', animated: true }, { id: 'e13', source: '1', target: '3', animated: true }, { id: 'e22a', source: '2', target: '2a', animated: true }, { id: 'e22b', source: '2', target: '2b', animated: true }, { id: 'e22c', source: '2', target: '2c', animated: true }, { id: 'e2c2d', source: '2c', target: '2d', animated: true }, ]; ``` At its most basic we can compute layouts similar to dagre, but because the layouting algorithm runs asynchronously we need to handle promises and update our Svelte state accordingly. The ELK reference is your new best friend We don't often recommend elkjs because its complexity makes it difficult for us to support folks when they need it. If you do decide to use it, you'll want to keep the original [Java API reference](https://eclipse.dev/elk/reference.html) handy. We've also included a few examples of some of the other layouting algorithms available, including a non-interactive force layout. ##### Honourable Mentions Of course, we can't go through every layouting library out there: we'd never work on anything else! Here are some other libraries we've come across that might be worth taking a look at: * If you want to use dagre or d3-hierarchy but need to support nodes with different dimensions, both [d3-flextree](https://github.com/klortho/d3-flextree) and [entitree-flex](https://github.com/codeledge/entitree-flex) look promising. * [Cola.js](https://github.com/tgdwyer/WebCola) looks like a promising option for so-called "constraint-based" layouts. We haven't had time to properly investigate it yet, but it looks like you can achieve results similar to d3-force but with a lot more control. #### Routing Edges If you don't have any requirements for edge routing, you can use one of the layouting libraries above to position nodes and let the edges fall wherever they may. Otherwise, you'll want to look into some libraries and techniques for edge routing. Your options here are more limited than for node layouting, but here are some resources we thought looked promising: * [Routing Orthogonal Diagram Connectors in JavaScript](https://medium.com/swlh/routing-orthogonal-diagram-connectors-in-javascript-191dc2c5ff70) If you do explore some custom edge routing options, consider contributing back to the community by writing a blog post or creating a library! You can use the editable edges functionality in Svelte Flow as a starting point for implementing a custom edge that can be routed along a specific path. ### Sub Flows A sub flow is a flowgraph contained within a node. These nested flows can operate independently or connect with nodes outside their parent node, making them perfect for organizing and grouping related nodes. This guide will show you how to implement sub flows and explain the available options for child nodes. ##### Defining Child Nodes To define a child node, use the `parentId` option (see all available options in the [node options section](/api-reference/types/node)). Child nodes are positioned relative to their parent, with `{ x: 0, y: 0 }` representing the top-left corner of the parent node. ```js highlight="parentId: 'A'" let nodes = $state.raw([ { id: 'A', data: { label: 'parent' }, position: { x: 0, y: 0 }, }, { id: 'B', data: { label: 'child' }, position: { x: 10, y: 10 }, parentId: 'A', }, ]); ``` Order of Nodes: Parents have to appear before their child nodes in the `nodes` array! ###### `extent: 'parent'` When a parent node has defined dimensions, you can restrict child node movement to stay within the parent's boundaries by setting `extent: 'parent'`. This prevents child nodes from being dragged outside their parent's area. Example: guides/subflows/a ##### App.svelte ```svelte ``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } html, body, #app { width: 100%; height: 100%; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### Child Node Behavior Child nodes maintain their relative position when the parent node is moved. While the `parentId` option establishes the parent-child relationship, child nodes can still be positioned outside their parent (unless `extent: 'parent'` is set). However, they will always move with their parent when it's dragged. In our examples, we use the built-in `group` node type for parent nodes, which provides a transparent background with a border. You can also use [any custom node type](/learn/layouting/sub-flows#any-node-can-be-a-parent-node) as a parent. Let's explore more complex scenarios by adding additional nodes and edges. You can create connections both within a group and between sub flows and outer nodes: Example: guides/subflows/b ##### App.svelte ```svelte ``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } html, body, #app { width: 100%; height: 100%; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ##### Using a Custom Parent Node To demonstrate the flexibility of parent nodes, let's modify our example by removing the label from node B and adding child nodes. This example shows how you can use any node type as a parent. We'll also set `draggable: false` on the child nodes to make them static. Example: guides/subflows/c ##### App.svelte ```svelte ``` ##### index.css ```css html, body { margin: 0; font-family: sans-serif; } html, body, #app { width: 100%; height: 100%; } .svelte-flow { --xy-background-color: #f7f9fb; } ``` ##### index.html ```html Svelte Flow Example
``` ##### index.ts ```ts import { mount } from 'svelte'; import App from './App.svelte'; import './index.css'; mount(App, { target: document.getElementById('app')!, }); ``` ### Migrate to v1 ### Migrate to Svelte Flow 1.0 Svelte Flow 1.0 is built from the ground up with Svelte 5 and includes many new features and improvements. This guide will help you migrate from Svelte Flow 0.x to 1.0. If you are looking for the Svelte Flow 0.x docs, please refer to [legacy.svelteflow.dev](https://legacy.svelteflow.dev). #### New features * **[Reconnect edges](/examples/edges/reconnect-edge)**: You can reconnect your edges by using the new `` component. It can be used to add custom reconnection points on custom edges. * **Keyboard navigation & A11y**: We added support for keyboard navigation and improved accessibility for screen readers. You can now tab through nodes and edges and move nodes with the arrow keys. Can be disabled via [**disableKeyboardA11y**](/api-reference/svelte-flow#disablekeyboarda11y) * **[Click connect](/examples/edges/click-connect)**: You can now create a new connection by clicking on a handle one by one. * **[Enhanced ViewportPortal](/api-reference/components/viewport-portal)**: You can now decide if you want to render something below or above the nodes & edges in the viewport. * **Improved [fitView](/api-reference/hooks/use-svelte-flow#fitview)**: We finetuned the `fitView` function to better work with dynamically added nodes. * **colorModeSSR** prop: You can pass a fallback color mode for server side rendering when colorMode is set to 'system'. * [**elevateNodesOnSelect**](/api-reference/svelte-flow#elevateNodesOnSelect) & [**elevateEdgesOnSelect**](/api-reference/svelte-flow#elevateEdgesOnSelect): Control if nodes & edges should be elevated via z-index when selected. * [**noDragClass, noWheelClass, noPanClass**](/api-reference/svelte-flow#style-props): You can now modify the class name used to disable dragging, panning and zooming. * [**onselectionchange**](/api-reference/svelte-flow#onselectionchange) & [**useOnSelectionChange**](/api-reference/hooks/use-on-selection-change): You can now listen to selection changes via a callback #### Breaking changes ##### `nodes` & `edges` are now using `$state.raw` instead of `writable` Svelte 5 introduces runes which are now getting used for nodes and edges. **Old API** ```js const nodes = writable([...]); const edges = writable([...]); ``` **New API** ```js let nodes = $state.raw([...]); let edges = $state.raw([...]); ``` ##### Updating Nodes & Edges Previously it was possible to update single node properties. Theoretically, this would also be possible with `$state`, however the [performance implications](https://svelte.dev/playground/e6f804ba6da348bc8b6a0a13c59672cb?version=5.19.0) of this are unfortunately too great, so we opted to using `$state.raw`. This means that `nodes` and `edges` are to be treated as immutable from now on. If you are making updates manually make sure you: 1. create a new node/edge object, when updating a property. 2. reassign the nodes/edges array (this was technically required before anyway) ```js nodes[0].position.x = 100; // won't work const newNode = { ...nodes[0] }; newNode.position.x = 100; nodes[0] = newNode; // not enough to trigger an update nodes = [...nodes]; // this will make it work nodes = nodes.map((node) => { if (node.id === '1') { return { ...node, position: { ...node.position, x: 100 } }; } return node; }); // also works updateNode('1', (node) => ({ ...node, position: { ...node.position, x: 100 }, })); // using the updateNode helper from useSvelteFlow ``` ##### `nodes` & `edges` need to be bound from `` **Old API** ```js ``` **New API** ```js ``` If `nodes` and `edges` live in a separate module, you can use [function bindings](https://svelte.dev/docs/svelte/bind#Function-bindings). ```js // store.svelte.js let nodes = $state.raw([...]); let edges = $state.raw([...]); export const getNodes = () => nodes; export const getEdges = () => edges; export const setNodes = (newNodes) => nodes = newNodes; export const setEdges = (newEdges) => edges = newEdges; ``` ```js // BaseComponent.svelte ``` ##### Custom Node & Edge Props This is by enlarge a general change in Svelte 5, but it does have quite a big impact on typing the props of Custom Nodes & Edges. **Old API** ```js // CustomNode.svelte type $$Props = NodeProps; export let data: $$Props['data']; export let position: $$Props['position']; export let selected: $$Props['selected']; ``` **New API** ```js let { data, position, selected } : NodeProps = $props(); ``` ##### Hooks Hooks now return reactive values instead of writables. Because `$state` values cannot be [returned by functions directly](https://svelte.dev/docs/svelte/$state#Passing-state-into-functions) we have to return an object with a `.current` property to keep reactivity. In this regard, we are [following the official trend](https://svelte.dev/docs/svelte/svelte-reactivity#MediaQuery) set by the Svelte library authors. **Old API** ```js const edges = useEdges(); $: console.log(edges); ``` **New API** ```js const edges = useEdges(); $inspect(edges.current); ``` Note that in case of `useNodes`, `useEdges` and `useViewport` reassignments to `.current` work! ```js const nodes = useNodes(); function updateNodes() { nodes.current = [...] } ``` ##### Binding the viewport Binding the viewport now works natively in Svelte 5. You can either access the internal viewport or bind your very own viewport object to be used instead. **Old API** ```js const viewport = writable({ x: 100, y: 100, zoom: 1.25 }); ``` **New API** ```js let viewport = $state < Viewport > { x: 100, y: 100, zoom: 1.25 }; ; ``` ##### Custom Connection Line Using a custom Connection Line was possible before by passing it to a [slot](https://svelte.dev/docs/svelte/legacy-slots). In Svelte Flow 1.0 we introduced a new prop called `connectionLineComponent`for this. **Old API** ```js ``` **New API** ```js ``` ##### `onEdgeCreate` becomes `onbeforeconnect` `onedgecreate` was called before a new edge was created. This is now called `onbeforeconnect` to better align with events like [`onbeforeconnect`](/api-reference/svelte-flow#onbeforedelete). **Old API** ```js ({...connection, id: crypto.randomUUID()})} /> ``` **New API** ```js ({ ...connection, id: crypto.randomUUID() })} /> ``` ##### `` becomes [``](/api-reference/components/edge-label) The `EdgeLabelRenderer` component is now called `EdgeLabel`. As it was just a simple Portal to begin with, the naming of it being a "renderer" was a bit misleading. To add to this, the new `EdgeLabel` component now also handles clicks on the label automatically and is aware of what edge it belongs to. **Old API** ```js filename="CustomEdge.svelte"
My Edge Label
``` **New API** ```js filename="CustomEdge.svelte"
My Edge Label
``` ### Remove Attribution If you’re considering removing the attribution, we’d first like to mention: **If you’re using Svelte Flow at your organization and making money from it**, we rely on your support to keep Svelte Flow developed and maintained under an MIT License. Before you remove the attribution, [see the ways you can support Svelte Flow to keep it running](/support-us). **Are you using Svelte Flow for a personal project?** Great! Go ahead and remove the attribution. You can support us by reporting any bugs you find, sending us screenshots of your projects, and starring us on [Github](https://github.com/xyflow/xyflow). If you start making money using Svelte Flow or use it in an organization in the future, we would ask that you re-add the attribution or become a Github or Open Collective Sponsor. Thank you for supporting us ✌🏻 * [the xyflow team](https://xyflow.com/about) To remove our attribution in the corner of your application you can pass `hideAttribution` through `proOptions` prop to the `` component. ```svelte filename="App.svelte" ```