Open SourceReactnode basedgraph

React Flow - A Library for Rendering Interactive Graphs

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: [email protected].

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 graphStyles = { width: '100%', height: '500px' };

const BasicGraph = () => <ReactFlow elements={elements} style={graphStyles} />;

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 these 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 dont 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. As with the nodes you can select the type by passing it to the edge in the elements list:

const elements = [
  { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 5, y: 5 } },
  { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
  { id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 150 } },
  { id: '4', data: { label: 'Node 4' }, 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' }
];

These are the available edge types:

If you want like to create a custom node or edge type you can look at the source of the custom node example. There we implement a custom node component and then 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 Graph = () => {
  const [elements, setElements] = useState(initialElements);
  const onElementsRemove = (elementsToRemove) =>
      setElements(els => removeElements(elementsToRemove, els));

  return (
    <ReactFlow
      elements={elements}
      style={graphStyles}
      onElementsRemove={onElementsRemove}
    />
  );
}

Plugins

React Flow comes with two plugins: Graph controls and a mini map. The controls panel comes with a zoom-in, zoom-out and focus-graph button. You can pass css styles to it or use the default styles which look like this:

The default mini map looks like this:

If you want to add these plugins to your graph you just need to pass them as childrens to your React Flow component:

import React, { useState } from 'react';
import ReactFlow, { MiniMap, Controls } from 'react-flow-renderer';

const elements = [
  { id: '1', type: 'input', data: { label: 'Node' }, position: { x: 0, y: 0 } }
];

const Graph = () => {
  return (
    <ReactFlow
      elements={elements}
      style={{ width: '100%', height: '500px' }}
    >
      <MiniMap
        nodeColor={n => {
          if (n.type === 'input') return 'blue';
          if (n.type === 'output') return 'green';
          if (n.type === 'default') return 'red';

          return 'gray';
        }}
      />
      <Controls />
  );
}

In the above example we are using the nodeColor property to change the color of displayed nodes. You can adjust the look of the mini map 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 remarks, feel free to contact me via mail or twitter or post an issue on Github. Best wishes and stay safe everyone!

Comments