Implementing a scrollbar for React Flow

Christian Mähler
4 min readFeb 22, 2022

--

Have you ever tried to implement a graph editor in React? If yes, then you probably stumbled upon React Flow when looking for a ready-to-use library. React Flow is an incredible powerful lib that is well maintained, well documented and has an active developer community.

At evoach, we help to make coaching digital. We do that by offering a tool to coaches to model their coaching sessions as a chatbot. This tool is a domain-specific chatbot builder that comprises components and workflows that explicitly address the needs of business coaching chatbots.

To implement this chatbot builder, we use React Flow. When we were starting with the editor, we worked with small graphs (which we call “modules” as a coach would call it) with around 30–50 nodes and edges. It turned out that the first customers required larger graphs with approx. 450 nodes and edges.

We found it very cumbersome to navigate in these large graphs by clicking/dragging the React Flow canvas and we were looking for something like a scrollbar. We ended up implementing not a real scrollbar but some kind of “jump bar” for ourselves. This post is about how we did that.

There were two things we were familiar with and that helped a lot to implement such a “jump bar”:

First, there is a capability to quickly center the current canvas view to a certain point in the canvas (please note that the coordinates are the React Flow projected coordinates and not the browser window coordinates). Consider this snippet:

import {useStore, useZoomPanHelper} from ‘react-flow-renderer’;

const store = useStore();

const { setCenter} = useZoomPanHelper();

const [tx, ty, ts] = store.getState().transform;

setCenter(tx, ty, ts);

React Flow has its own state management (Redux) and you can get the state via its store. store.getState().transform returns the current center as tx, ty and the current scale as ts. If you call setCenter with you own canvas coordinates, e.g. the coordinates of a node, then you center the canvas to that coordinate. And that’s the second important ingredient: filtering nodes. You can filter all nodes by:

import {useStoreActions, Elements, isNode} from ‘react-flow-renderer’;

// … set up initialElements with some nodes and edges, i.e., pass your own graph

const [elements, setElements] = useState<Elements>(initialElements);

const setStoreElements = useStoreActions((actions) => actions.setElements);

const allNodes = elements.filter(isNode);

Now, in allNodes, we have all React Flow nodes available. If we select a node (first node in the example), we can center the canvas on its position (and keep the scale) by:

import {useStore, useZoomPanHelper, XYPosition} from ‘react-flow-renderer’;

const store = useStore();

const { setCenter} = useZoomPanHelper();

const [, , ts] = store.getState().transform;

const nodePosition: XYPosition= allNodes[0].position;

setCenter(nodePosition.x, nodePosition.y, ts);

The idea of our “jump bar” is derived from these easy capabilities: make a visual representation of all nodes and when clicking on one node, get the coordinates and center canvas to coordinates of that node.

The result looks like this:

Not so many elements in the “jump bar”

On the right hand side you see the “jump bar” alongside the React Flow canvas. The mini-map at the left bottom corner is a React Flow feature. The “jump bar” contains blocks of grey and yellow. The colours reflect our own color coding for different types of custom nodes (visible on the left hand side in the canvas). If you click on one of the blocks, the corresponding node is centred in the canvas.

The first element is rendered at the top of the “jump bar”, the last one at the bottom. The elements in between are rendered in the relative distance to these elements depending on their y coordinates in the React Flow canvas. The height of the blocks is automatically reduced, depending on the number of nodes. For a large 400+ node graph it looks like this:

“Jump bar” for 400+ nodes

Even if you can’t exactly determine which element is meant, you can easily spot the yellow nodes and the structure of the document. You can now navigate very quickly in the canvas by clicking on the grey or yellow blocks.

The developed component contains some specific handlers for our use case and for our custom nodes that’s why I can’t share it here. But if you’re interested in the source code drop me a message in the comments.

--

--

Christian Mähler

Passionate about software development. Pragmatic and enthusiastic.