Events
React Flow provides comprehensive event handling for nodes, edges, connections, selections, and viewport changes.
Table of Contents
- Node Events
- Edge Events
- Connection Events
- Selection Events
- Viewport Events
- Pane Events
- Init and Delete Events
- Error Handling
Node Events
Click Events
import { ReactFlow, NodeMouseHandler, Node } from '@xyflow/react';
function NodeClickExample() {
const onNodeClick: NodeMouseHandler = (event, node) => {
console.log('Node clicked:', node.id, node.data);
};
const onNodeDoubleClick: NodeMouseHandler = (event, node) => {
console.log('Node double-clicked:', node.id);
};
const onNodeContextMenu: NodeMouseHandler = (event, node) => {
event.preventDefault();
console.log('Node right-clicked:', node.id);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Drag Events
import { ReactFlow, OnNodeDrag, NodeMouseHandler } from '@xyflow/react';
function NodeDragExample() {
const onNodeDragStart: NodeMouseHandler = (event, node) => {
console.log('Drag started:', node.id);
};
const onNodeDrag: node, nodes) => {
console.log('Dragging:', node.id, 'at', node.position);
console.log('All dragged nodes:', nodes.map(n => n.id));
};
const onNodeDragStop: NodeMouseHandler = (event, node) => {
console.log('Drag stopped:', node.id, 'at', node.position);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Hover Events
import { ReactFlow, NodeMouseHandler } from '@xyflow/react';
function NodeHoverExample() {
const onNodeMouseEnter: NodeMouseHandler = (event, node) => {
console.log('Mouse entered:', node.id);
};
const onNodeMouseMove: NodeMouseHandler = (event, node) => {
console.log('Mouse moving over:', node.id);
};
const onNodeMouseLeave: NodeMouseHandler = (event, node) => {
console.log('Mouse left:', node.id);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Edge Events
Click Events
import { ReactFlow, EdgeMouseHandler } from '@xyflow/react';
function EdgeClickExample() {
const onEdgeClick: EdgeMouseHandler = (event, edge) => {
console.log('Edge clicked:', edge.id);
console.log('From:', edge.source, 'To:', edge.target);
};
const onEdgeDoubleClick: EdgeMouseHandler = (event, edge) => {
console.log('Edge double-clicked:', edge.id);
};
const onEdgeContextMenu: EdgeMouseHandler = (event, edge) => {
event.preventDefault();
console.log('Edge right-clicked:', edge.id);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Hover Events
import { ReactFlow, EdgeMouseHandler } from '@xyflow/react';
function EdgeHoverExample() {
const onEdgeMouseEnter: EdgeMouseHandler = (event, edge) => {
console.log('Mouse entered edge:', edge.id);
};
const onEdgeMouseMove: EdgeMouseHandler = (event, edge) => {
console.log('Mouse moving over edge:', edge.id);
};
const onEdgeMouseLeave: EdgeMouseHandler = (event, edge) => {
console.log('Mouse left edge:', edge.id);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Edge Update and Reconnect
import { ReactFlow, OnReconnect, OnReconnectStart, OnReconnectEnd } from '@xyflow/react';
function EdgeReconnectExample() {
const onReconnect: newConnection) => {
console.log('Edge reconnected:', oldEdge.id);
console.log('New connection:', newConnection);
};
const onReconnectStart: edge, handleType) => {
console.log('Reconnect started:', edge.id, 'handle:', handleType);
};
const onReconnectEnd: edge, handleType, connectionState) => {
console.log('Reconnect ended:', edge.id);
console.log('Connection state:', connectionState);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
edgesReconnectable={true}
/>
);
}
Connection Events
Basic Connection
import { ReactFlow, OnConnect, addEdge } from '@xyflow/react';
import { useCallback } from 'react';
function ConnectionExample() {
const [edges, setEdges] = useState<Edge[]>([]);
const onConnect:
(connection) => {
console.log('Connection made:', connection);
console.log('Source:', connection.source);
console.log('Target:', connection.target);
console.log('Source Handle:', connection.sourceHandle);
console.log('Target Handle:', connection.targetHandle);
setEdges((eds) => addEdge(connection, eds));
},
[setEdges]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Connection Start and End
import { ReactFlow, OnConnectStart, OnConnectEnd } from '@xyflow/react';
function ConnectionLifecycleExample() {
const onConnectStart: { nodeId, handleId, handleType }) => {
console.log('Connection started from:', nodeId);
console.log('Handle:', handleId, 'Type:', handleType);
};
const onConnectEnd: connectionState) => {
console.log('Connection ended');
console.log('Was valid:', connectionState.isValid);
console.log('From node:', connectionState.fromNode?.id);
console.log('To node:', connectionState.toNode?.id);
console.log('From handle:', connectionState.fromHandle);
console.log('To handle:', connectionState.toHandle);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Validate Connections
import { ReactFlow, Connection, Edge, Node } from '@xyflow/react';
function ValidatedConnectionExample() {
const isValidConnection = (connection: Connection | Edge) => {
// Prevent self-connections
if (connection.source === connection.target) {
return false;
}
// Custom validation logic
const sourceNode = nodes.find(n => n.id === connection.source);
const targetNode = nodes.find(n => n.id === connection.target);
// Prevent connections from output nodes
if (sourceNode?.type === 'output') {
return false;
}
// Prevent connections to input nodes
if (targetNode?.type === 'input') {
return false;
}
return true;
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
isValidConnection={isValidConnection}
/>
);
}
Selection Events
useOnSelectionChange Hook
import { useOnSelectionChange, OnSelectionChangeParams } from '@xyflow/react';
import { useCallback } from 'react';
function SelectionLogger() {
const nodes, edges }: OnSelectionChangeParams) => {
console.log('Selected nodes:', nodes.map(n => n.id));
console.log('Selected edges:', edges.map(e => e.id));
}, []);
useOnSelectionChange({
onChange,
});
return null;
}
function SelectionExample() {
return (
<ReactFlow nodes={nodes} edges={edges}>
<SelectionLogger />
</ReactFlow>
);
}
Selection Drag
import { ReactFlow, SelectionDragHandler } from '@xyflow/react';
function SelectionDragExample() {
const onSelectionDragStart: SelectionDragHandler = (event, nodes) => {
console.log('Selection drag started:', nodes.length, 'nodes');
};
const onSelectionDrag: SelectionDragHandler = (event, nodes) => {
console.log('Dragging selection:', nodes.map(n => n.id));
};
const onSelectionDragStop: SelectionDragHandler = (event, nodes) => {
console.log('Selection drag stopped');
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Selection Context Menu
import { ReactFlow, Node, Edge } from '@xyflow/react';
function SelectionContextMenuExample() {
const React.MouseEvent, nodes: Node[]) => {
event.preventDefault();
console.log('Context menu on selection:', nodes.map(n => n.id));
// Show custom context menu
// ... context menu logic
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Viewport Events
useOnViewportChange Hook
import { useOnViewportChange, Viewport } from '@xyflow/react';
import { useCallback } from 'react';
function ViewportLogger() {
const Viewport) => {
console.log('Viewport change started:', viewport);
}, []);
const Viewport) => {
console.log('Viewport:', {
x: viewport.x,
y: viewport.y,
zoom: viewport.zoom,
});
}, []);
const Viewport) => {
console.log('Viewport change ended:', viewport);
}, []);
useOnViewportChange({
onStart,
onChange,
onEnd,
});
return null;
}
Move Events
import { ReactFlow, OnMove } from '@xyflow/react';
function MoveExample() {
const onMove: viewport) => {
console.log('Viewport moved to:', viewport);
};
const onMoveStart: viewport) => {
console.log('Move started from:', viewport);
};
const onMoveEnd: viewport) => {
console.log('Move ended at:', viewport);
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Pane Events
Click Events
import { ReactFlow } from '@xyflow/react';
import { MouseEvent } from 'react';
function PaneClickExample() {
const MouseEvent) => {
console.log('Pane clicked at:', event.clientX, event.clientY);
};
const MouseEvent) => {
event.preventDefault();
console.log('Pane right-clicked');
};
const MouseEvent | WheelEvent) => {
console.log('Pane scrolled');
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Mouse Events
import { ReactFlow } from '@xyflow/react';
import { MouseEvent } from 'react';
function PaneMouseExample() {
const MouseEvent) => {
console.log('Mouse entered pane');
};
const MouseEvent) => {
console.log('Mouse moving over pane');
};
const MouseEvent) => {
console.log('Mouse left pane');
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Init and Delete Events
Initialization
import { ReactFlow, OnInit, ReactFlowInstance } from '@xyflow/react';
function InitExample() {
const onInit: ReactFlowInstance) => {
console.log('React Flow initialized');
console.log('Viewport:', reactFlowInstance.getViewport());
reactFlowInstance.fitView();
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Delete Events
import { ReactFlow, OnNodesDelete, OnEdgesDelete, OnBeforeDelete } from '@xyflow/react';
function DeleteExample() {
const onNodesDelete: => {
console.log('Nodes deleted:', nodes.map(n => n.id));
};
const onEdgesDelete: => {
console.log('Edges deleted:', edges.map(e => e.id));
};
const onBeforeDelete: ({ nodes, edges }) => {
console.log('About to delete:', nodes.length, 'nodes and', edges.length, 'edges');
// Return true to allow deletion, false to cancel
const confirmed = window.confirm('Delete selected elements?');
return confirmed;
};
const nodes, edges }) => {
console.log('Deleted:', nodes.length, 'nodes and', edges.length, 'edges');
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}
Error Handling
import { ReactFlow, OnError } from '@xyflow/react';
function ErrorHandlingExample() {
const onError: message) => {
console.error(`React Flow Error [${code}]:`, message);
// Handle specific error codes
if (code === '010') {
console.error('Handle must be rendered inside a custom node');
}
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
/>
);
}