Context Menu
The onNodeContextMenu event can be used to show a custom menu when right-clicking a node. This example shows a simple menu with buttons to duplicate or delete the clicked node.
import React, { useCallback, useRef, useState } from 'react';
import {
ReactFlow,
Background,
useNodesState,
useEdgesState,
addEdge,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { initialNodes, initialEdges } from './initialElements';
import ContextMenu from './ContextMenu';
const Flow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const [menu, setMenu] = useState(null);
const ref = useRef(null);
const onConnect = useCallback(
(params) => setEdges((els) => addEdge(params, els)),
[setEdges],
);
const onNodeContextMenu = useCallback(
(event, node) => {
// Prevent native context menu from showing
event.preventDefault();
// Calculate position of the context menu. We want to make sure it
// doesn't get positioned off-screen.
const pane = ref.current.getBoundingClientRect();
setMenu({
id: node.id,
top: event.clientY < pane.height - 200 && event.clientY,
left: event.clientX < pane.width - 200 && event.clientX,
right: event.clientX >= pane.width - 200 && pane.width - event.clientX,
bottom:
event.clientY >= pane.height - 200 && pane.height - event.clientY,
});
},
[setMenu],
);
// Close the context menu if it's open whenever the window is clicked.
const onPaneClick = useCallback(() => setMenu(null), [setMenu]);
return (
<ReactFlow
ref={ref}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onPaneClick={onPaneClick}
onNodeContextMenu={onNodeContextMenu}
fitView
style={{ backgroundColor: "#F7F9FB" }}
>
<Background />
{menu && <ContextMenu onClick={onPaneClick} {...menu} />}
</ReactFlow>
);
};
export default Flow;