DEV Community

Cover image for Make interactive node-based graphs with React Flow. πŸ“ˆ
Vaibhav Khulbe
Vaibhav Khulbe

Posted on • Updated on

Make interactive node-based graphs with React Flow. πŸ“ˆ

Recently I was browsing some React libraries I need to work on. My criteria for selection was to find new and not so many famous ones but they should also be useful for scalable projects. I hunted various categories from app state management to real-time web sockets. While those were useful and were used by thousands of developers, there was this one which was someone hidden under some big names.

This is React Flow, and as described in their repo:

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.

I chose this because I think it's useful to make interactive graphs uniquely and yes, it's quite easy to get started! So, let's make something, let's make a cool node-based graph with React Flow. 😎

Well, first some features πŸ˜‹

Here are the top features or reasons why you should use React Flow library in your React app:

  1. Easy to integrate and work on: It wouldn't take you more than 5 mins to see your first graph live in the app. That's what I call 'easy'!

  2. Comes with extra plugins: You want a minimap just like you see in Sublime Text or you may want to add controls to your graph with panning/zooming? Say no more. The support is great and can be done with less code.

  3. Customizable: The entire library can be worked on multiple nodes, interactivities, and styles.

Let's start! πŸ‘¨β€πŸ’»

Ring Ring

Ring ring!

1. Installation:

Just grab your old friend NPM and run the following command (of course after you're done creating a React app):

npm install react-flow-renderer

Make sure it's installed correctly by going to your package.json file and looking for react-flow-renderer as a dependency.

2. Creating our first graph:

We need to clear out a few terms first. Here are some:

  • Elements: It's an object which is like a container of all the 'nodes' and the 'edges'.

  • Nodes: These are the individual boxes which may contain some text or information.

  • Edges: This is like a connector between two nodes. If you want the graph to show a connection between two or more nodes, you create edges. These can be characterised by the presence of a source and a target attribute.

  • Node types: There are three of them available. The first, 'input πŸŸͺ' which can also be the source node. Second is the 'default 🟧' similar to the default node you get and the third one is the 'output 🟩' that can be used to show the result of a process. As we know the library is highly customisable so we can create our node type as a 'custom 🟨' one.

  • Edge types: Similar to node types you get a 'straight', 'default' and a 'step' type. You can even go ahead and have a custom edge type!

  • Graph control plugin: A very handy plugin to add features like zoom-in, zoom-out and focus on the graph.

Graph control

  • Mini map plugin: If you have a complex or a large graph, this will show you a map of the entire diagram on a small box from where you get the overview.

Mini map

Okay, enough, I'll use these terms from now on.

To make a new graph we need to add elements, some styling and render them. First, make the elements object containing the necessary data for your nodes.

const elements = [
  { id: "1", data: { label: "Parent" }, position: { x: 500, y: 150 } },
  { id: "2", data: { label: "First child" }, position: { x: 400, y: 250 } },
  { id: "e1-2", source: "1", target: "2", animated: true }

We make 2 nodes here with unique id value, some labels and default positions with respective x and y coordinate values. The third object is the edge that connected the source node with id 1 to target node. Also, for that fancy dotted animation, we set the boolean value to true.

Next, we need to add basic styles to our nodes. This is required to render or else, you'll be greeted with the following error:

"The React Flow parent container needs a width and a height to render the graph."

Something you don't want to mess with (which I did because I thought styles aren't necessary! Meh...)

const graphStyles = { width: "100%", height: "500px" };

We simply provide what it said in the error. A default value of width and height.

Next, we make the BasicGraph function which needs elements and style attributes inside the <ReactFlow /> component.

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

Let's render it by passing the component inside our return:

export default function App() {
  return <BasicGraph />;

Panning and dragging node demo

Save it and boom! You made your first graph in a few minutes. How easy!

3. Create a custom node:

For this, we make a new element object called customElement but this time, let's add styles inside this one because we need a custom style, data and the starting position.

const customElement = [
    id: "1",
    style: {
      background: "#454052",
      width: 200,
      color: "#fff",
      fontSize: "20px",
      fontFamily: "Helvetica",
      boxShadow: "5px 5px 5px 0px rgba(0,0,0,.10)"
    data: { label: "My custom node" },
    position: { x: 500, y: 250 }
    id: "2",
    style: {
      background: "#fff",
      width: 400,
      color: "#454052",
      fontSize: "25px",
      fontFamily: "Helvetica",
      boxShadow: "5px 5px 5px 0px rgba(0,0,0,.10)"
    data: { label: "My second custom node πŸ˜‰" },
    position: { x: 550, y: 300 }

See how we have different id values, use custom style just like the CSS-in-JS concept and have a label. Most of this is self-explanatory as this is really simple to use and implement.

Custom node demo

This is what we get after making two custom nodes.

4. Experiment with edge styles:

Let's hop on to edges! Here, we change the elements object we made earlier for nodes as per our requirement. Here, I've made quite a complex one:

const elements = [
    id: "1",
    type: "input",
    data: { label: "Master Node" },
    position: { x: 50, y: 50 }
  { 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: "5", data: { label: "Node 5" }, position: { x: 750, y: 250 } },
    id: "6",
    data: { label: "Node 6" },
    position: { x: 800, y: 300 },
    type: "output"
  { id: "e1-2", source: "3", target: "2", type: "straight" },
  { id: "e1-3", source: "1", target: "3", type: "default" },
  { id: "e1-4", source: "1", target: "4", type: "default" },
  { id: "e1-5", source: "5", target: "2", type: "step", animated: true },
  { id: "e1-6", source: "1", target: "6", type: "step" }

It's not as confusing as it may seem. We've simply created a master node with id of 1. Notice how I made its type as input. Node number 2, 3, 4 and 5 are just normal children. As for the 6th one, we made it an output type.

For connections between the edges, we use the typical source - target pair of attributes. One good thing to note is the different lines you get, that comes from the type of the edge.

Multi node demo

Bonus! If you need to make your node or edge type, look at this example.

Here's the entire Sandbox of the above example:

Discussion (10)

saiprasad1996 profile image
Sai Prasad

Great library! Been playing with it for a while. How do we save and restore custom nodes? Any ideas?
Saving and restoring plain default nodes work. Ref -

vaibhavkhulbe profile image
Vaibhav Khulbe Author

I don’t know much about saving and restoring custom nodes for this. Maybe you can start a new issue in its repo?

saiprasad1996 profile image
Sai Prasad

Thanks Vaibhav for your quick response. I've figured out the way to achieve the functionality. FYI, you can create custom nodes and register the names with ReactFlow component and use the same name as the node type to be able to save and restore custom components. You can refer this link to get a clearer picture of what I was talking about -
Look out for ColorSelectorNode.js and setElements() function usage

Thread Thread
vaibhavkhulbe profile image
Vaibhav Khulbe Author

Nice, thanks for sharing!

archdj profile image
Divyansh Jamuaar

This looks great. Which library do you prefer for automatic node positioning?

adhemukhlis profile image
Mukhlis Adhe Purwanto

actually for automatic position requires the dagre library from npm, for details you can see in the documentation

sorry for my bad english

vaibhavkhulbe profile image
Vaibhav Khulbe Author

Thanks for sharing!

vaibhavkhulbe profile image
Vaibhav Khulbe Author

Thanks! As for the automatic node positioning I haven't used any such library.

psnehanshu profile image
Snehanshu Phukon • Edited

The edges overlap all-over, not a great experience.

sskanishk profile image
Kanish Malviya

How to avoid overlapping of edges (connection lines) and it's label?