Adding Interactivity
Beginner · 2 min read · Updated Nov 5, 2026
React Flow allows developers to build interactive node-based applications where users can drag nodes, select elements, connect nodes, and manage workflow diagrams dynamically. By using React Hooks, state management, and built-in event handlers, you can transform a static flow diagram into a fully interactive workflow editor.
Handling Change Events
Change events allow React Flow to respond to user interactions such as dragging nodes, selecting elements, and removing edges. You can use onNodesChange and onEdgesChange to track and update changes in your workflow.
import { useCallback, useState } from 'react';
import {
ReactFlow,
applyNodeChanges,
applyEdgeChanges,
} from '@xyflow/react';
const onNodesChange = useCallback(
(changes) => {
setNodes((nodes) =>
applyNodeChanges(changes, nodes)
);
},
[]
);
const onEdgesChange = useCallback(
(changes) => {
setEdges((edges) =>
applyEdgeChanges(changes, edges)
);
},
[]
);
These handlers ensure that node and edge updates are reflected in the React application state.
Defining Nodes and Edges
Before adding interactivity, define the initial nodes and edges for your React Flow diagram. Each node requires a unique ID, position, and data, while each edge requires source and target node IDs.
const initialNodes = [
{
id: '1',
type: 'input',
position: { x: 100, y: 50 },
data: { label: 'Start' },
},
{
id: '2',
position: { x: 300, y: 150 },
data: { label: 'Process' },
},
];
const initialEdges = [
{
id: 'e1-2',
source: '1',
target: '2',
},
];
This structure provides the foundation for building interactive workflow diagrams and visual node editors.
Managing Node and Edge State
React Flow uses React state to manage dynamic changes in controlled flows. The useState Hook stores node and edge data, allowing your application to update the canvas whenever users interact with its elements.
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
By managing these states, you can dynamically update workflow elements without manually manipulating the DOM.
Adding Event Handlers to React Flow
Event handlers connect React Flow interactions with your application state. Use onNodesChange and onEdgesChange to handle changes such as node dragging, element selection, and deletion.
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView
/>
These properties make your workflow canvas responsive to user actions and keep the displayed diagram synchronized with React state.
Handling Node Connections
React Flow allows users to create connections by dragging from one node handle to another. The onConnect event detects these interactions, while the addEdge() utility adds the new connection to the existing edge state.
import { addEdge } from '@xyflow/react';
const onConnect = useCallback(
(params) => {
setEdges((edges) => addEdge(params, edges));
},
[]
);
This functionality makes it easy to build interactive workflow builders, flowchart editors, and visual programming applications.
Passing Connection Handlers to ReactFlow
After defining the connection handler, pass it to the ReactFlow component through the onConnect property. This enables users to connect nodes directly on the canvas.
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
/>
Now users can drag between connection handles to create new edges and dynamically extend their workflows.
Building a Fully Interactive React Flow
Combine node state, edge state, and event handlers to create a complete interactive flow editor. React Flow supports node dragging, element selection, edge connections, multi-selection, and keyboard-based deletion.
import { useCallback, useState } from 'react';
import {
ReactFlow,
Background,
Controls,
applyNodeChanges,
applyEdgeChanges,
addEdge,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes = [
{
id: '1',
type: 'input',
position: { x: 100, y: 50 },
data: { label: 'Start Node' },
},
{
id: '2',
position: { x: 300, y: 150 },
data: { label: 'Process Node' },
},
];
const initialEdges = [
{
id: 'e1-2',
source: '1',
target: '2',
},
];
export default function App() {
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={{ width: '100%', height: '500px' }}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
>
<Background />
<Controls />
</ReactFlow>
</div>
);
}