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.

<script lang="ts">
  import { writable } from 'svelte/store';
  import { SvelteFlow, Background, type Node, type Edge } from '@xyflow/svelte';
 
  import ContextMenu from './ContextMenu.svelte';
 
  import { initialNodes, initialEdges } from './nodes-and-edges';
 
  import '@xyflow/svelte/dist/style.css';
 
  const nodes = writable<Node[]>(initialNodes);
  const edges = writable<Edge[]>(initialEdges);
 
  let menu: { id: string; top?: number; left?: number; right?: number; bottom?: number } | null;
  let width: number;
  let height: number;
 
  function handleContextMenu({ detail: { 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.
    menu = {
      id: node.id,
      top: event.clientY < height - 200 ? event.clientY : undefined,
      left: event.clientX < width - 200 ? event.clientX : undefined,
      right: event.clientX >= width - 200 ? width - event.clientX : undefined,
      bottom: event.clientY >= height - 200 ? height - event.clientY : undefined
    };
  }
 
  // Close the context menu if it's open whenever the window is clicked.
  function handlePaneClick() {
    menu = null;
  }
</script>
 
<div style="height:100vh;" bind:clientWidth={width} bind:clientHeight={height}>
  <SvelteFlow
    {nodes}
    {edges}
    on:nodecontextmenu={handleContextMenu}
    on:paneclick={handlePaneClick}
    fitView
  >
    <Background />
    {#if menu}
      <ContextMenu
        onClick={handlePaneClick}
        id={menu.id}
        top={menu.top}
        left={menu.left}
        right={menu.right}
        bottom={menu.bottom}
      />
    {/if}
  </SvelteFlow>
</div>