Panning and Zooming
The default pan and zoom behavior of React Flow is inspired by
slippy maps. You pan by dragging your
pointer and zoom by scrolling. You can customize this behavior easily with the
interaction and
keyboard props on the <ReactFlow />
component.
Viewport configurations
Here we will list and explain some configurations that other tools use.
Default viewport controls
As mentioned above, the ReactFlow default controls are as follows:
pan:pointer dragzoom:pinch or scrollselect:shift + pointer drag
Example: learn/zoom-pan
App.jsx
import { useCallback } from 'react';
import {
Background,
ReactFlow,
addEdge,
useEdgesState,
useNodesState,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes } from './nodes';
import { initialEdges } from './edges';
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 (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
colorMode="system"
>
<Background/>
</ReactFlow>
);
}
export default Flow;edges.js
export const initialEdges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e1-3', source: '1', target: '3' },
];index.css
html,
body {
margin: 0;
font-family: sans-serif;
}
#app {
width: 100vw;
height: 100vh;
}index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Flow Example</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.jsx"></script>
</body>
</html>index.jsx
import { createRoot } from 'react-dom/client';
import App from './App';
import './index.css';
const container = document.querySelector('#app');
const root = createRoot(container);
root.render(<App />);nodes.js
export const initialNodes = [
{
id: '1',
data: { label: 'Node 1' },
position: { x: 150, y: 0 },
},
{
id: '2',
data: { label: 'Node 2' },
position: { x: 0, y: 150 },
},
{
id: '3',
data: { label: 'Node 3' },
position: { x: 300, y: 150 },
},
];Design tool viewport controls
If you prefer figma/sketch/design tool controls you can set
panOnScroll and
selectionOnDrag to true and
panOnDrag to false:
pan:scroll, middle / right mouse drag, space + pointer dragzoom:pinch or cmd + scrollselect:pointer drag
Example: learn/zoom-pan-2
App.jsx
import { useCallback } from 'react';
import {
ReactFlow,
addEdge,
SelectionMode,
useEdgesState,
useNodesState,
Background,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes } from './nodes';
import { initialEdges } from './edges';
const panOnDrag = [1, 2];
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 (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
panOnScroll
selectionOnDrag
panOnDrag={panOnDrag}
selectionMode={SelectionMode.Partial}
fitView
colorMode="system"
>
<Background />
</ReactFlow>
);
}
export default Flow;edges.js
export const initialEdges = [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e1-3', source: '1', target: '3' },
];index.css
html,
body {
margin: 0;
font-family: sans-serif;
}
#app {
width: 100vw;
height: 100vh;
}index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Flow Example</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.jsx"></script>
</body>
</html>index.jsx
import { createRoot } from 'react-dom/client';
import App from './App';
import './index.css';
const container = document.querySelector('#app');
const root = createRoot(container);
root.render(<App />);nodes.js
export const initialNodes = [
{
id: '1',
data: { label: 'Node 1' },
position: { x: 150, y: 0 },
},
{
id: '2',
data: { label: 'Node 2' },
position: { x: 0, y: 150 },
},
{
id: '3',
data: { label: 'Node 3' },
position: { x: 300, y: 150 },
},
];In this example we also set selectionMode="partial" to be able to add nodes to a
selection that are only partially selected.