react-flow · existential-birds — Claude Code skill: what it does, how to install
Provides workflow diagram patterns using @xyflow/react. Helps the agent build custom nodes, handle dynamic connection points, and manage the graph viewport.
npx skills add existential-birds/beagle --skill react-flow -a claude-codeWhat react-flow does
The skill guides your coding agent when generating graph visualisations and interactive workflows with @xyflow/react. To use the generated components, your project needs @xyflow/react installed and its stylesheet imported from @xyflow/react/dist/style.css.
It covers typed nodes and edges via NodeProps and EdgeProps, as well as standard shapes like smoothstep or step. Connection points use the Handle component. Any interactive button inside a node must receive the nodrag class; without it, clicking an input drags the entire node.
Programmatic graph manipulation relies on the useReactFlow hook for actions like fitView, zoomIn, and element deletion. For interactive connections, the instructions apply EdgeLabelRenderer with nodrag nopan styling to preserve button click events.
What it helps with
- build custom graph nodes with typed data using
NodeProps - create custom edges with interactive delete buttons using
EdgeLabelRenderer - control viewport scale and focus programmatically with
useReactFlow - configure dynamic connection ports using
HandleandPosition
Example prompts for the agent
- Create a custom process node with two target handles and status indicators
- Add a delete button to the edge between nodes using EdgeLabelRenderer
- Build a controlled flow with useNodesState and a fitView button
How to install react-flow
1Skills CLI (Vercel)
npx skills add existential-birds/beagle --skill react-flow -a claude-code2Manually: put the files in place
~/.claude/skills/react-flow/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/react-flow/
1Skills CLI (Vercel)
npx skills add existential-birds/beagle --skill react-flow -a codex2Manually: put the files in place
.agents/skills/react-flow/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add existential-birds/beagle --skill react-flow -a cursor2Manually: put the files in place
.cursor/skills/react-flow/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install existential-birds/beagle react-flow2Manually: put the files in place
.github/skills/react-flow/SKILL.md1Skills CLI (Vercel)
npx skills add existential-birds/beagle --skill react-flow -a gemini-cli2Platform CLI
gemini skills install https://github.com/existential-birds/beagle --path plugins/beagle-react/skills/react-flowManually: put the files in place
.devin/skills/react-flow/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add existential-birds/beagle --skill react-flow -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about react-flow
How to install react-flow in Claude Code?
Run npx skills add existential-birds/beagle --skill react-flow -a claude-code in your terminal. This adds the skill definition to Claude Code.
What does the react-flow skill do?
It provides instructions for building diagrams with @xyflow/react. The skill covers custom node and edge components, handles, and viewport helpers.
Why do interactive elements inside custom nodes need the nodrag class?
React Flow intercepts mouse events to drag nodes across the canvas. Adding className="nodrag" keeps clicks and form inputs working inside the node.
Source text
SKILL.md · Apache-2.0
---
name: react-flow
description: React Flow (@xyflow/react) for workflow visualization with custom nodes and edges. Use when building graph visualizations, creating custom workflow nodes, implementing edge labels, or controlling viewport. Triggers on ReactFlow, @xyflow/react, Handle, NodeProps, EdgeProps, useReactFlow, fitView.
---
# 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
```bash
pnpm add @xyflow/react
```
### Basic Setup
```typescript
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 (
<div style={{ width: '100vw', height: '100vh' }}>
<ReactFlow nodes={initialNodes} edges={initialEdges}>
<Background />
<Controls />
<MiniMap />
</ReactFlow>
</div>
);
}
export default Flow;
```
## Core Concepts
### Nodes
Nodes are the building blocks of the graph. Each node has:
- `id`: Unique identifier
- `type`: Node type (built-in or custom)
- `position`: { x, y } coordinates
- `data`: Custom data object
```typescript
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 node
- `input`: No target handles
- `output`: No source handles
- `group`: Container for other nodes
### Edges
Edges connect nodes. Each edge requires:
- `id`: Unique identifier
- `source`: Source node ID
- `target`: Target node ID
```typescript
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 curve
- `straight`: Straight line
- `step`: Orthogonal with sharp corners
- `smoothstep`: Orthogonal with rounded corners
### Handles
Handles are connection points on nodes. Use `Position` enum for placement:
```typescript
import { Handle, Position } from '@xyflow/react';
<Handle type="target" position={Position.Top} />
<Handle 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:
```typescript
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 (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
/>
);
}
```
### useReactFlow Hook
Access the React Flow instance for programmatic control:
```typescript
import { useReactFlow } from '@xyflow/react';
function FlowControls() {
const {
getNodes,
getEdges,
setNodes,
setEdges,
addNodes,
addEdges,
deleteElements,
fitView,
zoomIn,
zoomOut,
getNode,
getEdge,
updateNode,
updateEdge,
} = useReactFlow();
return (
<button onClick={() => fitView()}>Fit View</button>
);
}
```
## Custom Nodes
Define custom nodes using `NodeProps<T>` with typed data:
```typescript
import { NodeProps, Node, Handle, Position } from '@xyflow/react';
export type CustomNode = Node<{ label: string; status: 'active' | 'inactive' }, 'custom'>;
function CustomNodeComponent({ data, selected }: NodeProps<CustomNode>) {
return (
<div className={`px-4 py-2 ${selected ? 'ring-2' : ''}`}>
<Handle type="target" position={Position.Top} />
<div className="font-bold">{data.label}</div>
<Handle type="source" position={Position.Bottom} />
</div>
);
}
```
Register with `nodeTypes`:
```typescript
const nodeTypes: NodeTypes = { custom: CustomNodeComponent };
<ReactFlow nodeTypes={nodeTypes} />
```
### Key Patterns
- **Multiple Handles**: Use `id` prop and `style` for 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](./references/custom-nodes.md) for detailed patterns including styling, aviation map pins, and dynamic handles.
## Custom Edges
Define custom edges using `EdgeProps<T>` and path utilities:
```typescript
import { BaseEdge, EdgeProps, getBezierPath } from '@xyflow/react';
export type CustomEdge = Edge<{ status: 'normal' | 'error' }, 'custom'>;
function CustomEdgeComponent(props: EdgeProps<CustomEdge>) {
const [edgePath] = getBezierPath(props);
return (
<BaseEdge
id={props.id}
path={edgePath}
style={{ stroke: props.data?.status === 'error' ? '#ef4444' : '#64748b' }}
/>
);
}
```
### Path Utilities
- `getBezierPath()` - Smooth curves
- `getStraightPath()` - Straight lines
- `getSmoothStepPath()` - Orthogonal with rounded corners
- `getSmoothStepPath({ 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:
```typescript
import { EdgeLabelRenderer, BaseEdge, getBezierPath } from '@xyflow/react';
function ButtonEdge(props: EdgeProps) {
const [edgePath, labelX, labelY] = getBezierPath(props);
return (
<>
<BaseEdge id={props.id} path={edgePath} />
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
pointerEvents: 'all',
}}
className="nodrag nopan"
>
<button onClick={() => console.log('Delete')}>×</button>
</div>
</EdgeLabelRenderer>
</>
);
}
```
See [Custom Edges Reference](./references/custom-edges.md) for animated edges, time labels, and SVG text patterns.
## Viewport Control
Use `useReactFlow()` hook for programmatic viewport control:
```typescript
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](./references/viewport.md) for save/restore state, controlled viewport, and coordinate transformations.
## Events
React Flow provides comprehensive event handling:
### Node Events
```typescript
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);
};
<ReactFlow
onNodeClick={onNodeClick}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeClick}
/>
```
### Edge and Connection Events
```typescript
import { EdgeMouseHandler, OnConnect } from '@xyflow/react';
const onEdgeClick: EdgeMouseHandler = (event, edge) => console.log('Edge:', edge.id);
const onConnect: OnConnect = (connection) => console.log('Connected:', connection);
<ReactFlow onEdgeClick={onEdgeClick} onConnect={onConnect} />
```
### Selection and Viewport Events
```typescript
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](./references/events.md) for complete event catalog including validation, deletion, and error handling.
## Common Patterns
### Preventing Drag/Pan
```typescript
<input className="nodrag" />
<button className="nodrag nopan">Click me</button>
```
### Connection Validation
```typescript
const isValidConnection = (connection: Connection) => {
return connection.source !== connection.target; // Prevent self-connections
};
<ReactFlow isValidConnection={isValidConnection} />
```
### Adding Nodes on Click
```typescript
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
```typescript
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:
```typescript
import { ReactFlow, ReactFlowProvider, useReactFlow } from '@xyflow/react';
function Controls() {
const { fitView } = useReactFlow(); // Must be inside provider
return <button onClick={() => fitView()}>Fit View</button>;
}
function App() {
return (
<ReactFlowProvider>
<Controls />
<ReactFlow nodes={nodes} edges={edges} />
</ReactFlowProvider>
);
}
```
## Implementation gates
Use these **sequenced checks** before treating an integration as done (they target common footguns, not style preferences).
1. **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.
2. **Stable `nodeTypes` / `edgeTypes`** — Do not pass a fresh object literal every render; define maps outside the component or memoize with `useMemo` and correct deps. **Pass:** no remount flicker or “maximum update depth” / runaway updates when only selection or viewport changes.
3. **Provider boundary** — Components that call `useReactFlow()` must be descendants of `ReactFlowProvider`, 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](./references/custom-nodes.md) - NodeProps typing, Handle component, dynamic handles, styling patterns
- [Custom Edges](./references/custom-edges.md) - EdgeProps typing, path utilities, EdgeLabelRenderer, animated edges
- [Viewport](./references/viewport.md) - useReactFlow methods, fitView options, coordinate conversion
- [Events](./references/events.md) - Node/edge/connection events, selection handling, viewport changes
© existential-birds · Apache-2.0 · existential-birds/beagle
Similar skills
Everything for Frontend and UI →react-flow by other authors comes first.