React Flow Implementation Quick Start import { ReactFlow, useNodesState, useEdgesState, addEdge } from '@xyflow/react'; import '@xyflow/react/dist/style.css';
const initialNodes = [ { id: '1', position: { x: 0, y: 0 }, data: { label: 'Node 1' } }, { id: '2', position: { x: 200, y: 100 }, data: { label: 'Node 2' } }, ];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
export default function Flow() { const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = useCallback( (connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges] );
return (
Core Patterns TypeScript Types import type { Node, Edge, NodeProps, BuiltInNode } from '@xyflow/react';
// Define custom node type with data shape type CustomNode = Node<{ value: number; label: string }, 'custom'>;
// Combine with built-in nodes type MyNode = CustomNode | BuiltInNode; type MyEdge = Edge<{ weight?: number }>;
// Use throughout app
const [nodes, setNodes] = useNodesState
Custom Nodes import { memo } from 'react'; import { Handle, Position, type NodeProps } from '@xyflow/react';
// Define node type type CounterNode = Node<{ count: number }, 'counter'>;
// Always wrap in memo for performance
const CounterNode = memo(function CounterNode({ data, isConnectable }: NodeProps
// Register in nodeTypes (define OUTSIDE component to avoid re-renders) const nodeTypes = { counter: CounterNode };
// Use in ReactFlow
Multiple Handles
// Use handle IDs when a node has multiple handles of same type
// Connect with specific handles const edge = { id: 'e1-2', source: '1', sourceHandle: 'a', target: '2', targetHandle: null };
Custom Edges import { BaseEdge, EdgeProps, getSmoothStepPath } from '@xyflow/react';
function CustomEdge({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data }: EdgeProps) { const [edgePath, labelX, labelY] = getSmoothStepPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, });
return (
<>
const edgeTypes = { custom: CustomEdge };
State Management
Controlled (Recommended for Production)
// External state with change handlers
const [nodes, setNodes] = useState
const onNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [] );
const onEdgesChange = useCallback( (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [] );
Using useReactFlow import { useReactFlow, ReactFlowProvider } from '@xyflow/react';
function FlowControls() { const { getNodes, setNodes, addNodes, updateNodeData, getEdges, setEdges, addEdges, fitView, zoomIn, zoomOut, setViewport, deleteElements, toObject, } = useReactFlow();
const addNode = () => {
addNodes({ id: ${Date.now()}, position: { x: 100, y: 100 }, data: { label: 'New' } });
};
return ; }
// Must wrap in provider when using useReactFlow
function App() {
return (
Updating Node Data const { updateNodeData } = useReactFlow();
// Merge with existing data updateNodeData(nodeId, { label: 'Updated' });
// Replace data entirely updateNodeData(nodeId, { newField: 'value' }, { replace: true });
Viewport & Fit View
// Fit on initial render
// Programmatic control const { fitView, setViewport, getViewport, zoomTo } = useReactFlow();
// Fit to specific nodes fitView({ nodes: [{ id: '1' }, { id: '2' }], duration: 500 });
// Set exact viewport setViewport({ x: 100, y: 100, zoom: 1.5 }, { duration: 300 });
Connection Validation const isValidConnection = useCallback((connection: Connection) => { // Prevent self-connections if (connection.source === connection.target) return false;
// Custom validation logic const sourceNode = getNode(connection.source); const targetNode = getNode(connection.target);
return sourceNode?.type !== targetNode?.type; }, []);
Common Props Reference <ReactFlow // Core data nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange}
// Custom types (define OUTSIDE component) nodeTypes={nodeTypes} edgeTypes={edgeTypes}
// Connections onConnect={onConnect} connectionMode={ConnectionMode.Loose} // Allow target-to-target isValidConnection={isValidConnection}
// Viewport fitView minZoom={0.1} maxZoom={4} defaultViewport={{ x: 0, y: 0, zoom: 1 }}
// Interaction nodesDraggable={true} nodesConnectable={true} elementsSelectable={true} panOnDrag={true} zoomOnScroll={true}
// Additional components
CSS Classes for Interaction Class Effect nodrag Prevent dragging when clicking element nowheel Prevent zoom on wheel events nopan Prevent panning from element nokey Prevent keyboard events (use on inputs) Additional Components
See ADDITIONAL_COMPONENTS.md for MiniMap, Controls, Background, NodeToolbar, NodeResizer.