React Flow is a library for building node-based graphs. You can easily implement custom node types and it comes with components like a mini-map and graph controls. Feel free to check out the examples or read the blog post to get started.
In order to make this library as flexible as possible we don’t do any state updates besides the positions. This means that you need to pass the functions to remove an element or connect nodes by yourself. You can implement your own ones or use the helper functions that come with the library.
npm install react-flow-renderer
This is a very basic example of how to use React Flow. There are more advanced examples in the example folder.
import React from 'react';
import ReactFlow from 'react-flow-renderer';
const elements = [
{ id: '1', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
// you can also pass a React component as a label
{ id: '2', data: { label: <div>Node 2</div> }, position: { x: 100, y: 100 } },
{ id: 'e1-2', source: '1', target: '2', animated: true },
];
const BasicFlow = () => <ReactFlow elements={elements} />;
elements
: array of nodes and edges (required)onElementClick(element: Node | Edge)
: element click callbackonElementsRemove(elements: Elements)
: element remove callbackonNodeDragStart(node: Node)
: node drag start callbackonNodeDragStop(node: Node)
: node drag stop callbackonConnect({ source, target })
: connect callbackonLoad(reactFlowInstance)
: editor load callbackonMove()
: move callbackonSelectionChange(elements: Elements)
: fired when element selection changesnodeTypes
: object with node typesedgeTypes
: object with edge typesstyle
: css propertiesclassName
: additional class nameconnectionLineType
: connection line type = straight
or bezier
connectionLineStyle
: connection style as svg attributesdeleteKeyCode
: default: 8
(delete)selectionKeyCode
: default: 16
(shift)snapToGrid
: default: false
snapGrid
: [x, y] array - default: [16, 16]
onlyRenderVisibleNodes
: default: true
isInteractive
: default: true
. If the graph is not interactive you can't drag any nodesselectNodesOnDrag
: default: true
minZoom
: default: 0.5
maxZoom
: default: 2
defaultZoom
: default: 1
You can receive a reactFlowInstance
by using the onLoad
callback:
import React from 'react';
import ReactFlow from 'react-flow-renderer';
const onLoad = (reactFlowInstance) => {
reactFlowInstance.fitView();
}
const BasicFlow = () => <ReactFlow onLoad={onLoad} elements={[]} />;
reactFlowInstance
has the following functions:
Transforms pixel coordinates to the internal React Flow coordinate system
project = (position: XYPosition): XYPosition
Fits view port so that all nodes are visible
fitView = ({ padding }): void
zoomIn = (): void
zoomOut = (): void
getElements = (): Elements
There are three different node types (default
, input
, output
) you can use. The node types differ in the number and types of handles. An input node has only a source handle, a default node has a source and a target and an output node has only a target handle. You create nodes by adding them to the elements
array of the ReactFlow
component.
Node example: { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }
id
: string (required)position
: { x: number, y: number } (required)data
: {} (required if you are using a standard type, otherwise depends on your implementation)type
: 'input' | 'output' | 'default' or a custom one you implementedstyle
: css propertiesclassName
: additional class nametargetPosition
: 'left' | 'right' | 'top' | 'bottom' handle position - default: 'top'sourcePosition
: 'left' | 'right' | 'top' | 'bottom' handle position - default: 'bottom'The standard node types are input
, default
and output
. The default node types object looks like this:
{
input: InputNode,
default: DefaultNode,
output: OutputNode
}
The keys represent the type names and the values are the components that get rendered.
If you want to introduce a new type you can pass a nodeTypes
object to the ReactFlow
component:
nodeTypes={{
special: MyCustomNode
}}
You could now use the type special
for a node.
The default
, input
and output
types would be still available except you overwrote one of them.
There is an example of a custom node implementation in the custom node example.
Your custom nodes are wrapped so that the basic functions like dragging or selecting work. Custom nodes receive the following props:
id
: stringdata
: objecttype
: stringselected
: booleansourcePosition
: stringtargetPosition
: stringWe export a Handle
component as a helper for your custom nodes:
import { Handle } from 'react-flow-renderer';
const targetHandleWithValidation = (
<Handle
type="target"
position="left"
isValidConnection={(connection) => connection.source === 'some-id'}
onConnect={params => console.log('handle onConnect', params)}
style={{ background: '#fff' }}
/>
);
type
: 'source' or 'target'id
: string - you only need this when you have multiple source or target handles otherwise the node id is usedposition
: 'left', 'right', 'top' or 'bottom' handle position - default: 'top' for type target, 'bottom' for type sourceonConnect
: function that gets triggered on connectisValidConnection
: function receives a connection { target: 'some-id', source: 'another-id' }
as param, returns a boolean - default: true
style
: css propertiesclassName
: additional class nameThe handle receives the additional class names connecting
when the connection line is above the handle and valid
if the connection is valid. You can find an example which uses these classes here.
If you need multiple source or target handles you can achieve this by creating a custom node. Normally you just use the id of a node for the source
or target
of an edge. If you have multiple source or target handles you need to pass an id to these handles. These ids get then added to the node id, so that you can connect a specific handle. If you have a node with an id = 1
and a handle with an id = a
you can connect this handle by using the id = 1__a
.
You can find an example of how to implement a custom node with multiple handles in the custom node example.
React Flow comes with three edge types (straight
, default
, step
). As the names indicate, the edges differ in the representation. The default type is a bezier edge. You create edges by adding them to your elements
array of the ReactFlow
component.
Edge example: { id: 'e1-2', type: 'straight', source: '1', target: '2', animated: true, label: 'edge label' }
If you wanted to display this edge, you would need a node with id = 1 (source node) and one with id = 2 (target node).
id
: string (required)source
: string (an id of a node) (required)target
: string (an id of a node) (required)type
: 'input', 'output', 'default' or a custom one you implementedanimated
: booleanstyle
: css properties for the edge line pathlabel
: stringlabelStyle
: css properties for the textlabelShowBg
: boolean - default: true
labelBgStyle
: css properties for the text backgroundYou can find an example with lots of different edges in the edges example.
The basic edge types are straight
, default
and step
. The default edgeTypes
object looks like this:
{
default: BezierEdge,
straight: StraightEdge,
step: StepEdge
}
The keys represent the type names and the values are the edge components.
If you want to introduce a new edge type you can pass an edgeTypes
object to the ReactFlow
component:
edgeTypes={{
special: MyCustomEdge
}}
Now you could use the new type special
for an edge.
The straight
, default
and step
types would still be available unless you overwrote one of them.
There is an implementation of a custom edge in the edges example.
React Flow comes with two background variants: dots and lines. You can use it by passing it as a children to the ReactFlow
component:
import ReactFlow, { Background } from 'react-flow-renderer';
const FlowWithBackground = () => (
<ReactFlow elements={elements}>
<Background
variant="dots"
gap={12}
size={4}
/>
</ReactFlow>
);
variant
: string - has to be 'dots' or 'lines' - default: dots
gap
: number - the gap between the dots or lines - default: 16
size
: number - the radius of the dots or the stroke width of the lines - default: 0.5
color
: string - the color of the dots or lines - default: #999
for dots, #eee
for linesstyle
: css propertiesclassName
: additional class nameYou can use the mini map plugin by passing it as a children to the ReactFlow
component:
import ReactFlow, { MiniMap } from 'react-flow-renderer';
const FlowWithMiniMap = () => (
<ReactFlow elements={elements}>
<MiniMap
nodeColor={(node) => {
switch (node.type) {
case 'input': return 'red';
case 'default': return '#00ff00';
case 'output': return 'rgb(0,0,255)';
default: return '#eee';
}
}}
/>
</ReactFlow>
);
nodeColor
: string or function - If you pass a color as a string all nodes will get that color. If you pass a function you can return a color depending on the passed node.nodeBorderRadius
: numbermaskColor
: stringstyle
: css propertiesclassName
: additional class nameThe control panel contains a zoom-in, zoom-out, fit-view and a lock/unlock button. You can use it by passing it as a children to the ReactFlow
component:
import ReactFlow, { Controls } from 'react-flow-renderer';
const FlowWithControls = () => (
<ReactFlow elements={elements}>
<Controls />
</ReactFlow>
);
showZoom
: boolean - default: trueshowFitView
: boolean - default: trueshowInteractive
: boolean - default: truestyle
: css propertiesclassName
: additional class nameIf you need access to the internal state and action of React Flow outside of the ReactFlow
component you can wrap it with the ReactFlowProvider
component:
import ReactFlow, { ReactFlowProvider } from 'react-flow-renderer';
const FlowWithOwnProvider = () => (
<ReactFlowProvider>
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onConnect={onConnect}
/>
</ReactFlowProvider>
);
It is used in the provider example.
There are two ways how you can style the graph pane and the elements. You can create your own CSS rules or pass style properties to the components.
Since we are rendering DOM nodes you can simply overwrite the styles with your own CSS rules.
The React Flow wrapper has the className react-flow
. If you want to change the graph background for example you can do:
.react-flow {
background: red;
}
.react-flow
- Outer container.react-flow__renderer
- Inner container.react-flow__zoompane
- Zoom & pan pane.react-flow__selectionpane
- Selection pane.react-flow__selection
- User selection.react-flow__edges
- Edges wrapper.react-flow__edge
- Edge element
.selected
is added when edge is selected.animated
is added when edge is animated.react-flow__edge-path
- Edge element path.react-flow__edge-text
- Edge text.react-flow__edge-textbg
- Edge text background.react-flow__connection
- Connection line.react-flow__connection-path
- Connection line path.react-flow__nodes
- Nodes wrapper.react-flow__node
- Node element
.selected
is added when edge is selected-${type}
is added (.react-flow__node-default
, .react-flow__node-input
, .react-flow__node-output
).react-flow__nodesselection
- Nodes selection.react-flow__nodesselection-rect
- Nodes selection rect.react-flow__handle
- Handle component
.react-flow__handle-bottom
is added when position = 'bottom'.react-flow__handle-top
is added when position = 'top'.react-flow__handle-left
is added when position = 'left'.react-flow__handle-right
is added when position = 'right'.react-flow__handle-connecting
is added when connection line is above a handle.react-flow__handle-valid
is added when connection line is above a handle and the connection is valid.react-flow__background
- Background component.react-flow__minimap
- Mini map component.react-flow__controls
- Controls componentYou could achieve the same effect by passing a style prop to the ReactFlow
component:
const FlowWithRedBg = (
<ReactFlow
elements={elements}
style={{ background: 'red', width: '100%' height: '300px' }}
/>
);
If you want to remove a node or connect two nodes with each other you need to pass a function to onElementsRemove
and onConnect
. In order to simplify this process there are some helper functions you can use:
import ReactFlow, { isNode, isEdge, removeElements, addEdge } from 'react-flow-renderer';
Returns true if element is an edge
isEdge = (element: Node | Edge): element is Edge
Returns true if element is a node
isNode = (element: Node | Edge): element is Node
Returns elements without the elements from elementsToRemove
removeElements = (elementsToRemove: Elements, elements: Elements): Elements
Returns elements array with added edge
addEdge = (edgeParams: Edge, elements: Elements): Elements
You can use these function as seen in this example or use your own ones.
Under the hood React Flow uses Easy Peasy for state handling.
If you need to access the internal state you can use the useStoreState
hook inside a child component of the ReactFlow
component:
import ReactFlow, { useStoreState } from 'react-flow-renderer';
const NodesDebugger = () => {
const nodes = useStoreState(state => state.nodes);
console.log(nodes);
return null:
}
const Flow = () => (
<ReactFlow elements={elements}>
<NodesDebugger />
</ReactFlow>
);
If you need more control you can wrap the ReactFlow
component with the ReactFlowProvider
component in order to be able to call useStoreState
outside of the ReactFlow
component.
You can find all examples in the example folder or check out the live versions:
You need to install the React Flow dependencies via npm install
and the ones of the examples cd example && npm install
.
If you want to contribute or develop some custom features the easiest way is to start the dev server:
npm run dev
This serves the content of the example
folder and watches changes inside the src
folder. The examples are using the source of the src
folder.
Testing is done with cypress. You can find all tests in the integration/flow
folder. In order to run the tests do:
npm run test
Special thanks to Andy Lindemann for a lot of helpful contributions!
React Flow was initially developed by webkid, a data visualization company from Berlin. If you need help or want to develop react-based tools or data visualizations, get in touch!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。