Sub Flows
Deprecation of parentNode
property! We have renamed the parentNode
option to parentId
in version 11.11.0. The old property is still supported
but will be removed in version 12.
A sub flow is a flow inside a node. It can be a separate flow or a flow that is connected with other nodes outside of its parent. This feature can also be used for grouping nodes. In this part of the docs we are going to build a flow with sub flows and show you the child node specific options.
Order of Nodes
It’s important that your parent nodes appear before their children in the
nodes
/ defaultNodes
array to get processed correctly.
Adding Child Nodes
If you want to add a node as a child of another node you need to use the parentId
(this was called parentNode
in previous versions) option (you can find a list of all options in the node options section). Once we do that, the child node is positioned relative to its parent. A position of { x: 0, y: 0 }
is the top left corner of the parent.
In this example we are setting a fixed width and height of the parent node by passing the style option. Additionally, we set the child extent to 'parent'
so that we can’t move the child nodes out of the parent node.
import { useCallback, useState } from 'react';
import {
ReactFlow,
addEdge,
applyEdgeChanges,
applyNodeChanges,
Background,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes } from './nodes';
import { initialEdges } from './edges';
const rfStyle = {
backgroundColor: '#D0C0F7',
};
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[setNodes],
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges],
);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges],
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
style={rfStyle}
attributionPosition="top-right"
>
<Background />
</ReactFlow>
);
}
export default Flow;
Using Child Specific Options
When you move the parent node you can see that the child nodes move, too. Adding a node to another node with the parentId
option, just does one thing: It positions it relatively to its parent. The child node is not really a child markup-wise. You can drag or position the child outside of its parent (when the extent: 'parent'
option is not set) but when you move the parent, the child moves with it.
In the example above we are using the group
type for the parent node but you can use any other type as well. The group
type is just a convenience node type that has no handles attached.
Now we are going to add some more nodes and edges. As you can see, we can connect nodes within a group and create connections that go from a sub flow to an outer node:
import { useCallback, useState } from 'react';
import {
ReactFlow,
addEdge,
applyEdgeChanges,
applyNodeChanges,
Background,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes } from './nodes';
import { initialEdges } from './edges';
const rfStyle = {
backgroundColor: '#D0C0F7',
};
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[setNodes],
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges],
);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges],
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
style={rfStyle}
attributionPosition="top-right"
>
<Background />
</ReactFlow>
);
}
export default Flow;
Using a Default Node Type as a Parent
Let’s remove the label of node B and add some child nodes. In this example you can see that you can use one of the default node types as parents, too. We also set the child nodes to draggable: false
so that they are not draggable anymore.
import { useCallback, useState } from 'react';
import {
ReactFlow,
addEdge,
applyEdgeChanges,
applyNodeChanges,
Background,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes } from './nodes';
import { initialEdges } from './edges';
const rfStyle = {
backgroundColor: '#D0C0F7',
};
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const onNodesChange = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[setNodes],
);
const onEdgesChange = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[setEdges],
);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges],
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
style={rfStyle}
attributionPosition="top-right"
>
<Background />
</ReactFlow>
);
}
export default Flow;