We just open sourced
"React Flow":
A library for rendering interactive node-based graphs with a smooth panning and zooming behaviour and lots of nice features and even some useful plugins like a mini map!
In this post I will show you a simple example of a React Flow application. If you want to start even faster you can directly go to the
documentation or check out the demo:
If we can help you to develop a custom node-based tool we are happy to hear from you:
info@webkid.io.
We updated the article to represent the current default styles
Key Features
React Flow not only renders a graph but also adds interactivity and comes with a lot of built-in features:
- Easy to use: Seamless zooming & panning behaviour and single and multi-selections of elements
- Customizable: Different node and edge types and support for custom nodes and edges
- Fast rendering: only elements that are in the view port are displayed
- Utils: Configurable snap-to-grid behaviour, background styles and graph helper functions
- Plugin system: Mini map and graph controls
- Reliable: Written in Typescript and tested with cypress
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 all functions that change the displayed nodes and edges by yourself. You can implement your own ones or use the
helper functions that come with the library.
Getting started
You can install React Flow via npm. Unfortunately react-flow
was already taken so you need to install react-flow-renderer
:
npm install react-flow-renderer
You can now integrate it in your React application. A simple graph could like like this:
import React from 'react';
import ReactFlow from 'react-flow-renderer';
const elements = [
{ id: '1', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
{ id: 'e1-2', source: '1', target: '2', animated: true },
];
const flowStyles = { height: 500 };
const BasicFlow = () => <ReactFlow elements={elements} style={flowStyles} />;
As you can see we are passing
elements
to the ReactFlow component. In the list of elements there are two nodes and an edge that connects the nodes with each other. You can identify the edge by the presence of a
source
and
target
attribute. The nodes have some initial positions so that they don't overlap. We are also passing a
style
in order to get some space for rendering the graph. You can find a full list of options in the
documenation. The example above would like this:
Node and Edge Types
A graph almost always has different node types. React Flow comes with three basic types: input
, default
and output
.
You can select the type by using the type
attribute of a node:
const elements = [
{
id: '1',
type: 'input',
data: { label: 'Input node' },
position: { x: 100, y: 5 },
},
{
id: '2',
type: 'default',
data: { label: 'Default node' },
position: { x: 100, y: 100 },
},
{
id: '3',
type: 'output',
data: { label: 'Output node' },
position: { x: 100, y: 200 },
},
];
The different node types look like this:
As you can see the handles which allows you to connect nodes and the color of the types are different.
You can customize these existing types by passing a label
and also a style
object with css rules:
const elements = [
{
id: '1',
style: { background: '#ffcc50', width: 100 },
data: { label: 'custom style' },
position: { x: 100, y: 5 },
},
];
This would look like this:
React Flow has the following edge types: straight
, default
, step
and smoothstep
. As with the nodes you can select the type by passing it to an edge in the elements list:
const elements = [
{
id: '1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 5, y: 5 },
},
{ id: '2', data: { label: 'straight' }, position: { x: 100, y: 100 } },
{ id: '3', data: { label: 'default' }, position: { x: 250, y: 150 } },
{ id: '4', data: { label: 'step' }, position: { x: 500, y: 200 } },
{ id: '5', data: { label: 'smoothstep' }, position: { x: 500, y: 200 } },
{ id: 'e1-2', source: '1', target: '2', type: 'straight' },
{ id: 'e1-3', source: '1', target: '3', type: 'default' },
{ id: 'e1-4', source: '1', target: '4', type: 'step' },
{ id: 'e1-5', source: '1', target: '5', type: 'smoothstep' },
];
These are the available edge types:
If you want like to create a custom node or edge type you can check out the
custom node example. There we implement a custom node component and make it available within the renderer by passing it to the React Flow component as a
nodeTypes
property.
Interactivity
As I pointed out earlier React Flow comes with some basic interactivity but doesn't do state updates for the rendered elements. You can zoom and pan and drag or select elements but if you want to add or remove a node for example you need to implement the function by yourself or use one of the
React Flow helper functions. Whenever the elements property change on the React Flow component we re-render the graph. So if you want to add a node for example you need to push a new node to your elements array and pass it to the React Flow component. If you want to remove a node you need to listen to the remove event by passing a function to
onElementsRemove
prop:
import React, { useState } from 'react';
import ReactFlow, { removeElements } from 'react-flow-renderer';
const initialElements = [
{
id: '1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 5, y: 5 },
},
];
const flowStyles = { height: 300 };
const Flow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
return (
<ReactFlow
elements={elements}
style={flowStyles}
onElementsRemove={onElementsRemove}
/>
);
};
Plugins
React Flow comes with several plugins:
Background,
Controls and
Mini Map. You can pass your own css styles or use the default styles. If you want to add a plugin to your graph you need to pass it as a children to your React Flow component:
import React, { useState } from 'react';
import ReactFlow, { MiniMap, Controls } from 'react-flow-renderer';
const nodeColor = (node) => {
if (node.type === 'input') return 'blue';
if (node.type === 'output') return 'green';
if (node.type === 'default') return 'red';
return 'gray';
};
const FlowWithPlugins = () => {
return (
<ReactFlow elements={[]} style={{ height: 500 }}>
<MiniMap nodeColor={nodeColor} />
<Controls />
</ReactFlow>
);
};
In the above example we are using the nodeColor
property to change the color of displayed nodes inside the mini map.
You can adjust the look by using the nodeColor
, nodeBorderRadius
, maskColor
or style
properties.
That's it
I hope that I could give you a good overview of React Flow. If you have any questions or feedback, feel free to contact me via
mail or
twitter or post an
issue on Github. Best wishes and stay safe everyone!