React Flow
/install react-flow
React Flow
React Flow (@xyflow/react) is a library for building node-based graphs, workflow editors, and interactive diagrams. It provides a highly customizable framework for creating visual programming interfaces, process flows, and network visualizations.
Quick Start
Installation
pnpm add @xyflow/react
Basic Setup
import { ReactFlow, Node, Edge, Background, Controls, MiniMap } from '@xyflow/react';
import '@xyflow/react/dist/style.css';
const initialNodes: Node[] = [
{
id: '1',
type: 'input',
data: { label: 'Input Node' },
position: { x: 250, y: 5 },
},
{
id: '2',
data: { label: 'Default Node' },
position: { x: 100, y: 100 },
},
{
id: '3',
type: 'output',
data: { label: 'Output Node' },
position: { x: 400, y: 100 },
},
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3' },
];
function Flow() {
return (
\x3Cdiv style={{ width: '100vw', height: '100vh' }}>
\x3CReactFlow nodes={initialNodes} edges={initialEdges}>
\x3CBackground />
\x3CControls />
\x3CMiniMap />
\x3C/ReactFlow>
\x3C/div>
);
}
export default Flow;
Core Concepts
Nodes
Nodes are the building blocks of the graph. Each node has:
id: Unique identifiertype: Node type (built-in or custom)position: { x, y } coordinatesdata: Custom data object
import { Node } from '@xyflow/react';
const node: Node = {
id: 'node-1',
type: 'default',
position: { x: 100, y: 100 },
data: { label: 'Node Label' },
style: { background: '#D6D5E6' },
className: 'custom-node',
};
Built-in node types:
default: Standard nodeinput: No target handlesoutput: No source handlesgroup: Container for other nodes
Edges
Edges connect nodes. Each edge requires:
id: Unique identifiersource: Source node IDtarget: Target node ID
import { Edge } from '@xyflow/react';
const edge: Edge = {
id: 'e1-2',
source: '1',
target: '2',
type: 'smoothstep',
animated: true,
label: 'Edge Label',
style: { stroke: '#fff', strokeWidth: 2 },
};
Built-in edge types:
default: Bezier curvestraight: Straight linestep: Orthogonal with sharp cornerssmoothstep: Orthogonal with rounded corners
Handles
Handles are connection points on nodes. Use Position enum for placement:
import { Handle, Position } from '@xyflow/react';
\x3CHandle type="target" position={Position.Top} />
\x3CHandle type="source" position={Position.Bottom} />
Available positions: Position.Top, Position.Right, Position.Bottom, Position.Left
State Management
Controlled Flow
Use state hooks for full control:
import { useNodesState, useEdgesState, addEdge, OnConnect } from '@xyflow/react';
import { useCallback } from 'react';
function ControlledFlow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect: OnConnect = useCallback(
(connection) => setEdges((eds) => addEdge(connection, eds)),
[setEdges]
);
return (
\x3CReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
/>
);
}
useReactFlow Hook
Access the React Flow instance for programmatic control:
import { useReactFlow } from '@xyflow/react';
function FlowControls() {
const {
getNodes,
getEdges,
setNodes,
setEdges,
addNodes,
addEdges,
deleteElements,
fitView,
zoomIn,
zoomOut,
getNode,
getEdge,
updateNode,
updateEdge,
} = useReactFlow();
return (
\x3Cbutton onClick={() => fitView()}>Fit View\x3C/button>
);
}
Custom Nodes
Define custom nodes using NodeProps\x3CT> with typed data:
import { NodeProps, Node, Handle, Position } from '@xyflow/react';
export type CustomNode = Node\x3C{ label: string; status: 'active' | 'inactive' }, 'custom'>;
function CustomNodeComponent({ data, selected }: NodeProps\x3CCustomNode>) {
return (
\x3Cdiv className={`px-4 py-2 ${selected ? 'ring-2' : ''}`}>
\x3CHandle type="target" position={Position.Top} />
\x3Cdiv className="font-bold">{data.label}\x3C/div>
\x3CHandle type="source" position={Position.Bottom} />
\x3C/div>
);
}
Register with nodeTypes:
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
\x3CReactFlow nodeTypes={nodeTypes} />
Key Patterns
- Multiple Handles: Use
idprop andstylefor positioning - Dynamic Handles: Call
useUpdateNodeInternals([nodeId])after adding/removing handles - Interactive Elements: Add
className="nodrag"to prevent dragging on inputs/buttons
See Custom Nodes Reference for detailed patterns including styling, aviation map pins, and dynamic handles.
Custom Edges
Define custom edges using EdgeProps\x3CT> and path utilities:
import { BaseEdge, EdgeProps, getBezierPath } from '@xyflow/react';
export type CustomEdge = Edge\x3C{ status: 'normal' | 'error' }, 'custom'>;
function CustomEdgeComponent(props: EdgeProps\x3CCustomEdge>) {
const [edgePath] = getBezierPath(props);
return (
\x3CBaseEdge
id={props.id}
path={edgePath}
style={{ stroke: props.data?.status === 'error' ? '#ef4444' : '#64748b' }}
/>
);
}
Path Utilities
getBezierPath()- Smooth curvesgetStraightPath()- Straight linesgetSmoothStepPath()- Orthogonal with rounded cornersgetSmoothStepPath({ borderRadius: 0 })- Orthogonal with sharp corners (step edge)
All return [path, labelX, labelY, offsetX, offsetY].
Interactive Labels
Use EdgeLabelRenderer for HTML-based labels with pointer events:
import { EdgeLabelRenderer, BaseEdge, getBezierPath } from '@xyflow/react';
function ButtonEdge(props: EdgeProps) {
const [edgePath, labelX, labelY] = getBezierPath(props);
return (
\x3C>
\x3CBaseEdge id={props.id} path={edgePath} />
\x3CEdgeLabelRenderer>
\x3Cdiv
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: 'all',
}}
className="nodrag nopan"
>
\x3Cbutton onClick={() => console.log('Delete')}>×\x3C/button>
\x3C/div>
\x3C/EdgeLabelRenderer>
\x3C/>
);
}
See Custom Edges Reference for animated edges, time labels, and SVG text patterns.
Viewport Control
Use useReactFlow() hook for programmatic viewport control:
import { useReactFlow } from '@xyflow/react';
function ViewportControls() {
const { fitView, zoomIn, zoomOut, setCenter, screenToFlowPosition } = useReactFlow();
// Fit all nodes in view
const handleFitView = () => fitView({ padding: 0.2, duration: 400 });
// Zoom controls
const handleZoomIn = () => zoomIn({ duration: 300 });
const handleZoomOut = () => zoomOut({ duration: 300 });
// Center on specific coordinates
const handleCenter = () => setCenter(250, 250, { zoom: 1.5, duration: 500 });
// Convert screen coordinates to flow coordinates
const addNodeAtClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
// Use position to add node
};
return null;
}
See Viewport Reference for save/restore state, controlled viewport, and coordinate transformations.
Events
React Flow provides comprehensive event handling:
Node Events
import { NodeMouseHandler, OnNodeDrag } from '@xyflow/react';
const onNodeClick: NodeMouseHandler = (event, node) => {
console.log('Node clicked:', node.id);
};
const onNodeDrag: OnNodeDrag = (event, node, nodes) => {
console.log('Dragging:', node.id);
};
\x3CReactFlow
onNodeClick={onNodeClick}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeClick}
/>
Edge and Connection Events
import { EdgeMouseHandler, OnConnect } from '@xyflow/react';
const onEdgeClick: EdgeMouseHandler = (event, edge) => console.log('Edge:', edge.id);
const onConnect: OnConnect = (connection) => console.log('Connected:', connection);
\x3CReactFlow onEdgeClick={onEdgeClick} onConnect={onConnect} />
Selection and Viewport Events
import { useOnSelectionChange, useOnViewportChange } from '@xyflow/react';
useOnSelectionChange({
onChange: ({ nodes, edges }) => console.log('Selected:', nodes.length, edges.length),
});
useOnViewportChange({
onChange: (viewport) => console.log('Viewport:', viewport.zoom),
});
See Events Reference for complete event catalog including validation, deletion, and error handling.
Common Patterns
Preventing Drag/Pan
\x3Cinput className="nodrag" />
\x3Cbutton className="nodrag nopan">Click me\x3C/button>
Connection Validation
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // Prevent self-connections
};
\x3CReactFlow isValidConnection={isValidConnection} />
Adding Nodes on Click
const { screenToFlowPosition, setNodes } = useReactFlow();
const onPaneClick = (event: React.MouseEvent) => {
const position = screenToFlowPosition({ x: event.clientX, y: event.clientY });
setNodes(nodes => [...nodes, { id: `node-${Date.now()}`, position, data: { label: 'New' } }]);
};
Updating Node Data
const { updateNodeData } = useReactFlow();
updateNodeData('node-1', { label: 'Updated' });
updateNodeData('node-1', (node) => ({ ...node.data, count: node.data.count + 1 }));
Provider Pattern
Wrap the app with ReactFlowProvider when using useReactFlow() outside the flow:
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
function Controls() {
const { fitView } = useReactFlow(); // Must be inside provider
return \x3Cbutton onClick={() => fitView()}>Fit View\x3C/button>;
}
function App() {
return (
\x3CReactFlowProvider>
\x3CControls />
\x3CReactFlow nodes={nodes} edges={edges} />
\x3C/ReactFlowProvider>
);
}
Implementation gates
Use these sequenced checks before treating an integration as done (they target common footguns, not style preferences).
- CSS in the bundle — Ensure
import '@xyflow/react/dist/style.css'runs in the app (entry or layout). Pass: nodes and edges have expected default styling; handles are visible and interactable. - Stable
nodeTypes/edgeTypes— Do not pass a fresh object literal every render; define maps outside the component or memoize withuseMemoand correct deps. Pass: no remount flicker or “maximum update depth” / runaway updates when only selection or viewport changes. - Provider boundary — Components that call
useReactFlow()must be descendants ofReactFlowProvider, and the flow must actually mount. Pass: no missing-context error at runtime; programmatic APIs (fitView, etc.) work where expected.
Reference Files
For detailed implementation patterns, see:
- Custom Nodes - NodeProps typing, Handle component, dynamic handles, styling patterns
- Custom Edges - EdgeProps typing, path utilities, EdgeLabelRenderer, animated edges
- Viewport - useReactFlow methods, fitView options, coordinate conversion
- Events - Node/edge/connection events, selection handling, viewport changes
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install react-flow - 安装完成后,直接呼叫该 Skill 的名称或使用
/react-flow触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
React Flow 是什么?
React Flow (@xyflow/react) for workflow visualization with custom nodes and edges. Use when building graph visualizations, creating custom workflow nodes, im... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 153 次。
如何安装 React Flow?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install react-flow」即可一键安装,无需额外配置。
React Flow 是免费的吗?
是的,React Flow 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
React Flow 支持哪些平台?
React Flow 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 React Flow?
由 Kevin Anderson(@anderskev)开发并维护,当前版本 v1.1.1。