Skip to Content
📣 We just released Svelte Flow 1.0 Alpha — try it out and give us your feedback!

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). Child nodes are positioned relative to their parent, with { x: 0, y: 0 } representing the top-left corner of the parent node.

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: Children have to appear before their parent 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.

<script lang="ts"> import { SvelteFlow, Background, type Node } from '@xyflow/svelte'; import '@xyflow/svelte/dist/style.css'; let nodes = $state.raw<Node[]>([ { id: 'A', type: 'group', data: {}, position: { x: 0, y: 0 }, style: 'width: 170px; height: 140px;', }, { id: 'A-1', type: 'input', data: { label: 'child' }, position: { x: 10, y: 10 }, parentId: 'A', }, { id: 'A-2', data: { label: "child with extent: 'parent'" }, position: { x: 10, y: 80 }, parentId: 'A', extent: 'parent', }, ]); let edges = $state.raw([]); </script> <SvelteFlow bind:nodes bind:edges fitView autoPanOnNodeDrag={false}> <Background /> </SvelteFlow>

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

<script lang="ts"> import { SvelteFlow, Background, type Node, type Edge } from '@xyflow/svelte'; import '@xyflow/svelte/dist/style.css'; let nodes = $state.raw<Node[]>([ { id: 'A', type: 'group', data: {}, position: { x: 0, y: 0 }, style: 'width: 170px; height: 140px;', }, { id: 'A-1', type: 'input', data: { label: 'child' }, position: { x: 10, y: 10 }, parentId: 'A', }, { id: 'A-2', data: { label: "child with extent: 'parent'" }, position: { x: 10, y: 80 }, parentId: 'A', extent: 'parent', }, { id: 'B', type: 'output', position: { x: -100, y: 200 }, data: { label: 'node b' }, }, { id: 'C', type: 'output', position: { x: 100, y: 200 }, data: { label: 'node c' }, }, ]); let edges = $state.raw<Edge[]>([ { id: 'a1-a2', source: 'A-1', target: 'A-2' }, { id: 'a2-b', source: 'A-2', target: 'B' }, { id: 'a2-c', source: 'A-2', target: 'C' }, ]); </script> <SvelteFlow bind:nodes bind:edges fitView autoPanOnNodeDrag={false}> <Background /> </SvelteFlow>

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.

<script lang="ts"> import { SvelteFlow, Background, type Node, type Edge } from '@xyflow/svelte'; import '@xyflow/svelte/dist/style.css'; let nodes = $state.raw<Node[]>([ { id: 'A', type: 'group', data: {}, position: { x: 0, y: 0 }, style: 'width: 170px; height: 140px;', }, { id: 'A-1', type: 'input', data: { label: 'child' }, position: { x: 10, y: 10 }, parentId: 'A', }, { id: 'A-2', data: { label: "child with extent: 'parent'" }, position: { x: 10, y: 80 }, parentId: 'A', extent: 'parent', }, { id: 'B', type: 'output', position: { x: -100, y: 200 }, data: {}, style: 'width: 170px; height: 140px;', }, { id: 'B-1', data: { label: 'child 1' }, position: { x: 50, y: 10 }, parentId: 'B', extent: 'parent', draggable: false, style: 'width: 60px;', }, { id: 'B-2', data: { label: 'child 2' }, position: { x: 10, y: 90 }, parentId: 'B', extent: 'parent', draggable: false, style: 'width: 60px;', }, { id: 'B-3', data: { label: 'child 3' }, position: { x: 100, y: 90 }, parentId: 'B', extent: 'parent', draggable: false, style: 'width: 60px;', }, { id: 'C', type: 'output', position: { x: 100, y: 200 }, data: { label: 'node c' }, }, ]); let edges = $state.raw<Edge[]>([ { id: 'a1-a2', source: 'A-1', target: 'A-2' }, { id: 'a2-b', source: 'A-2', target: 'B' }, { id: 'a2-c', source: 'A-2', target: 'C' }, ]); </script> <SvelteFlow bind:nodes bind:edges fitView autoPanOnNodeDrag={false}> <Background /> </SvelteFlow>
Last updated on