Skip to Content
LearnGetting StartedAdding Interactivity

Adding Interactivity

Now that we’ve built our first flow, let’s add interactivity so you can select, drag, and remove nodes and edges.

In this Getting Started tutorial, we’ll use React Flow as a “controlled component”. This is typically the most flexible and reliable approach for integrating it into your applications. (If you prefer, you can also work with React Flow in an uncontrolled way.

Handling Change Events

Continuing from Building a Flow, let’s dive into some essentials. To manage changes, we’ll be using useState with two helper functions from React Flow: applyEdgeChanges and applyNodeChanges. We can import these into our project like this:

import { useState, useCallback } from 'react'; import { ReactFlow, applyEdgeChanges, applyNodeChanges } from '@xyflow/react';

Next, we’re going to set up states for both the nodes and edges:

const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges);

Directly beneath that, we’ll add these two functions:

const onNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [], ); const onEdgesChange = useCallback( (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [], );

When you drag or select a node, the onNodesChange handler is triggered. The applyNodeChanges function then uses these change events to update the current state of your nodes. Here’s how it all comes together. Try clicking and dragging a node to move it around and watch the UI update in real time.

import { useState, useCallback } from 'react'; import { ReactFlow, Controls, Background, applyNodeChanges, applyEdgeChanges, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; const initialNodes = [ { id: '1', data: { label: 'Hello' }, position: { x: 0, y: 0 }, type: 'input', }, { id: '2', data: { label: 'World' }, position: { x: 100, y: 100 }, }, ]; const initialEdges = [ { id: '1-2', source: '1', target: '2', label: 'to the', type: 'step' }, ]; function Flow() { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges); const onNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [], ); const onEdgesChange = useCallback( (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [], ); return ( <div style={{ height: '100%' }}> <ReactFlow nodes={nodes} onNodesChange={onNodesChange} edges={edges} onEdgesChange={onEdgesChange} fitView > <Background /> <Controls /> </ReactFlow> </div> ); } export default Flow;

Handle Connections

One last piece is missing: connecting nodes manually. For this, we need to implement an onConnect handler and pass it to the <ReactFlow /> component:

import { useState, useCallback } from 'react'; import { ReactFlow, Controls, Background, applyNodeChanges, applyEdgeChanges, addEdge, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; const initialNodes = [ { id: '1', data: { label: 'Hello' }, position: { x: 0, y: 0 }, type: 'input', }, { id: '2', data: { label: 'World' }, position: { x: 100, y: 100 }, }, ]; const initialEdges = []; function Flow() { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges); const onNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [], ); const onEdgesChange = useCallback( (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [], ); const onConnect = useCallback( (params) => setEdges((eds) => addEdge(params, eds)), [], ); return ( <div style={{ height: '100%' }}> <ReactFlow nodes={nodes} onNodesChange={onNodesChange} edges={edges} onEdgesChange={onEdgesChange} onConnect={onConnect} fitView > <Background /> <Controls /> </ReactFlow> </div> ); } export default Flow;

Try to connect the two nodes by dragging from on handle to another one. That’s it. You’ve built a fully interactive flow.

That’s it for now :) You made it! If you want to move on, we recommend to check out the “Custom Nodes” guide.

Last updated on