Concepts
Introduction
React Flow is a library for building node-based applications.
We can use it to build
- simple static diagrams or
- data visualisations or
- complex visual editors.
We can implement
- custom node types
- custom edges
The library has builtin minimap and viewport controls
Built-in plugins in React Flow
<Background />
: implement some basic customisable background patterns<MiniMap />
: displays a small version of the graph in the corner<Controls />
: adds controls to zoon, center, and lock viewport<Panel />
: help to position content on top of viewport<NodeToolbar />
: render a toolbar attached to a node<NodeResizer />
: add resize funtionality to nodes
Terms and Definitions
3 key components in React Flow are:
- nodes
- edges
- handles
Nodes
- A node in React Flow is a React component.
- Each node has a x/y-coordinate, which declare where it's placed in the viewport
- Details of node options are available in: API: Nodes -> Node Options
- We can create custom nodes, to create better rendering effect, font etc.
Handles
- A handle (also called "port" in other libraries) is the place where an edge (connection) attaches to.
- Handles can be placed anywhere
- Default, a handle appears as a grey circle on border (top, bottom, left or right) of the node
- We can create as many as handles as we want
Edges
- An edge connects two nodes.
- Every edge needs a target and a source node.
- React Flow has 4 built-in edge types
- default
- smoothstep
- step
- straight
- Edge is SVG path that can be styled with CSS and customizable
- If a node has multiple handle, multiple edge can be created
Connection Line
React flow has built-in function to click-and-drag from one handle to another. The placeholder edge during dragging is called connection line. We can configure them according to props section
Viewport
All of React Flow exist in the viewport (screen). Viewport has three values:
x
y
zoom
User interact with viewport (move and magnify) by modifying these three values.
e.g.
- initial viewport as shown above. Where
x=0
,y=0
, andzoom=1
and - changed viewport as shown below. Where
x=51.94
,y=-33.42
, andzoom=1.73
Core Concepts
Learning objectives:
- Core concepts of React Flow
- How to create an interactive flow
What is a Flow:
- Flow consists of nodes or/and edges.
How to pass data into React Flow to render:
- pass arrays of
nodes
or/andedges
as props to<ReactFlow />
component
Property of node/edge:
- All node and edge ids need to be unique
- A node needs a position and a label
- An edge needs a source (
node id
) and a target (node id
) - Details of options are availabe in Node options and Edge options
Controlled or Uncontrolled
React Flow has two way of setup a flow
- controlled: you are in control of the state of the nodes and edge
- uncontrolled: nodes and edges are handled by React Flow internally. Details in Uncontrolled Flow
import { useState } from 'react';
import ReactFlow from 'reactflow';
import 'reactflow/dist/style.css';
const initialNodes = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 25 },
},
{
id: '2',
// you can also pass a React component as a label
data: { label: <div>Default Node</div> },
position: { x: 100, y: 125 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 250, y: 250 },
},
];
const initialEdges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3', animated: true },
];
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
return <ReactFlow nodes={nodes} edges={edges} fitView />;
}
export default Flow;
Basic Functionality
Code in previous section cannot do any select, drag or remove action, as default React Flow doesn't do any internal state update. It only handle viewport when a controlled flow is setup.
To select, drag and remove nodes and edges, we need implement onNodesChange
and onEdgeChange
handler of <ReactFlow />
component
import { useCallback, useState } from 'react';
import ReactFlow, { applyEdgeChanges, applyNodeChanges } from 'reactflow';
import 'reactflow/dist/style.css';
import initialNodes from './nodes.js';
import initialEdges from './edges.js';
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]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange} // handle node change
onEdgesChange={onEdgesChange}
fitView
/>
);
}
export default Flow;
Where:
- When
<ReactFlow />
trigger a change (node init, node drag, edge select), theonNodesChange
handler gets called. applyNodeChanges
handler is provided by library (using zustand for internal state management), so it's nearly out of box.applyNodeChanges
handler returns an updated array of nodes that used by<ReactFlow />
component
With onNodesChange
and onEdgesChange
handler, we can have an interactive flow chart with following interactions:
- selectable nodes and edges
- draggable nodes
- removable nodes and edges (
deleteKeyCode
prop allow remove node via Backspace) - multi-selection area by pressing Shift
- multi-selection by pressing command
To simplify code above, we can directly use hook
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
Connecting Nodes
Final pazzle of interactive <ReactFlow />
component is onConnect
handler. It can be used to handle new connections between nodes
...
import ReactFlow, { addEdge, applyEdgeChanges, applyNodeChanges } from 'reactflow';
...
function Flow() {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
const onNodesChange = useCallback(
...
);
const onEdgesChange = useCallback(
...
);
const onConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
/>
);
}
export default Flow;
Plugin Components
MiniMap
To have overview, we can use built-in MiniMap
component, and add it as children in ReactFlow
component
import ReactFlow, { MiniMap } from 'reactflow';
import 'reactflow/dist/style.css';
import defaultNodes from './nodes.js';
import defaultEdges from './edges.js';
const nodeColor = (node) => {
switch (node.type) {
case 'input':
return '#6ede87';
case 'output':
return '#6865A5';
default:
return '#ff0072';
}
};
function Flow() {
return (
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} fitView>
<MiniMap nodeColor={nodeColor} nodeStrokeWidth={3} zoomable pannable />
</ReactFlow>
);
}
export default Flow;
Details of <MiniMap />
component is in API page
Background
<Background />
component can be used to display pattern background
import { useState } from 'react';
import ReactFlow, { Background, Panel } from 'reactflow';
import 'reactflow/dist/style.css';
import defaultNodes from './nodes.js';
import defaultEdges from './edges.js';
function Flow() {
const [variant, setVariant] = useState('cross');
return (
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} fitView>
<Background color="#ccc" variant={variant} />
<Panel>
<div>variant:</div>
<button onClick={() => setVariant('dots')}>dots</button>
<button onClick={() => setVariant('lines')}>lines</button>
<button onClick={() => setVariant('cross')}>cross</button>
</Panel>
</ReactFlow>
);
}
export default Flow;
Panel
<Panel />
component is helper component that can be used to display content on top of React Flow viewport
import ReactFlow, { Background, Panel } from 'reactflow';
import 'reactflow/dist/style.css';
import './style.css';
const nodes = [
{
id: '1',
data: { label: 'this is an example flow for the <Panel /> component' },
position: { x: 0, y: 0 },
},
];
function Flow() {
return (
<ReactFlow nodes={nodes} fitView>
<Panel position="top-left">top-left</Panel>
<Panel position="top-center">top-center</Panel>
<Panel position="top-right">top-right</Panel>
<Panel position="bottom-left">bottom-left</Panel>
<Panel position="bottom-center">bottom-center</Panel>
<Panel position="bottom-right">bottom-right</Panel>
<Background variant="cross" />
</ReactFlow>
);
}
export default Flow;
Packages
React Flow packages available on npm
@reactflow/core
: export main<ReactFlow />
component,<ReactFlowProvider />
, hooks and util functions@reactflow/background
exports Background component@reactflow/controls
exports Controls and ControlButton component@reactflow/minimap
exports MiniMap component@reactflow/node-toolbar
exports NodeToolbar component@reactflow/node-resizer
exports NodeResizer component