Skip to content

Introduction to Edges ​

Edges are the links connecting your nodes, forming a map. Each edge runs from one handle to another, and can be customized to your liking.

Remember, every edge is unique and thus requires a unique id, a source and target node id.

For the full list of options available for an edge, check out the Edge Type.

Adding Edges to the Graph ​

Edges are generally created by adding them to the mode-value (using v-model) or to the edges prop of the Vue Flow component. This can be done dynamically at any point in your component's lifecycle.

vue

<script setup>
import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core'

const elements = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    label: 'Node 1',
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    label: 'Node 2',
  }
]);

onMounted(() => {
  elements.value.push({
    id: 'e1-2',
    source: '1',
    target: '2',
  })
})
</script>

<template>
  <VueFlow v-model="elements"/>
</template>
vue

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { Elements } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core'

const elements = ref<Elements>([
  {
    id: '1',
    position: { x: 50, y: 50 },
    label: 'Node 1',
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    label: 'Node 2',
  }
]);

onMounted(() => {
  elements.value.push({
    id: 'e1-2',
    source: '1',
    target: '2',
  })
})
</script>

<template>
  <VueFlow v-model="elements"/>
</template>

If you are working with more complex graphs that necessitate extensive state access, the useVueFlow composable should be employed. The addEdges action is available through useVueFlow, allowing you to add edges straight to the state.

What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a Sidebar or Toolbar.

vue
<script setup>
import { VueFlow, useVueFlow } from '@vue-flow/core'

const initialNodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    label: 'Node 1',
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    label: 'Node 2',
  }
])

const { addEdges } = useVueFlow()

onMounted(() => {
  // add an edge after mount
  addEdges([
     {
        source: '1',
        target: '2',
        
        // if a node has multiple handles of the same type,
        // you should specify which handle to use by id
        sourceHandle: null,
        targetHandle: null,
     }
  ])
})
</script>

<template>
  <VueFlow :nodes="initialNodes" />
</template>

Removing Edges from the Graph ​

Similar to adding edges, edges can be removed from the graph by removing them from the mode-value (using v-model) or from the edges prop of the Vue Flow component.

vue

<script setup>
import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core'

const elements = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    label: 'Node 1',
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    label: 'Node 2',
  },
  {
    id: 'e1-2',
    source: '1',
    target: '2',
  }
]);

onMounted(() => {
  elements.value.splice(2, 1)
})
</script>

<template>
  <VueFlow v-model="elements"/>
</template>

When working with complex graphs with extensive state access, you should use the useVueFlow composable. The removeEdges action is available through useVueFlow, allowing you to remove edges straight from the state.

What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a Sidebar, Toolbar or the Edge itself.

vue
<script setup>
import { VueFlow, useVueFlow } from '@vue-flow/core'

const elements = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    label: 'Node 1',
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    label: 'Node 2',
  },
  {
    id: 'e1-2',
    source: '1',
    target: '2',
  }
])

const { removeEdges } = useVueFlow()

onMounted(() => {
  // remove an edge after mount
  removeEdges('e1-2')
  
  // or remove multiple edges
  removeEdges(['e1-2', 'e2-3'])
})
</script>

<template>
  <VueFlow v-model="elements" />
</template>

Updating Edge Data ​

Since edges are reactive object, you can update their data at any point by simply mutating it. This allows you to change the label, or even add new properties to the data object at any point in time.

There are multiple ways of achieving this, here are some examples:

vue
<!-- CustomEdge.vue -->
<script setup>
import { useEdge } from '@vue-flow/core'

// `useEdge` returns us the edge object straight from the state
// since the node obj is reactive, we can mutate it to update our edges' data
const { edge } = useEdge()

function onSomeEvent() {
  edge.data = {
    ...edge.data,  
    hello: 'world',
  }
  
  // you can also mutate properties like `selectable` or `animated`
  edge.selectable = !edge.selectable
  edge.animated = !edge.animated
}
</script>
ts
import  { useVueFlow } from '@vue-flow/core'

const instance = useVueFlow()

// find the node in the state by its id
const edge = instance.findEdge(edgeId)

edge.data = {
  ...edge.data,
  hello: 'world',
}

// you can also mutate properties like `selectable` or `animated`
edge.selectable = !edge.selectable
edge.animated = !edge.animated
vue
<script setup>
import { ref } from 'vue'

const elements = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
    data: {
      hello: 'world',
    }
  },
  {
      id: '2',
      label: 'Node 2',
      position: { x: 50, y: 250 },
  },
  {
      id: 'e1-2',
      source: '1',
      target: '2',
  },
])

function onSomeEvent(edgeId) {
  const edge = elements.value.find((edge) => edge.id === edgeId)
  edge.data = {
    ...elements.value[0].data,
    hello: 'world',
  }

  // you can also mutate properties like `selectable` or `animated`
  edge.selectable = !edge.selectable
  edge.animated = !edge.animated
}
</script>

<template>
  <VueFlow v-model="elements" />
</template>

Predefined Edge-Types ​

Vue Flow provides several built-in edge types that you can leverage immediately. The included node types are default (bezier), step, smoothstep and straight.

Default Edge (Bezier) ​

The default edge is a bezier curve that connects two nodes.

Step Edge ​

A step edge has a straight path with a step towards the target.

Smoothstep Edge ​

The same as the step edge though with a border radius on the step (rounded step).

Straight Edge ​

A simple straight path.

User-Defined Edges ​

On top of the default edge types mentioned earlier, you can create as many custom edge-types as you need. Edge-types are determined from your edges' definitions.

vue
<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

import CustomEdge from './CustomEdge.vue'
import SpecialEdge from './SpecialEdge.vue'

export const edges = ref([
  {
    id: 'e1-2',
    source: '1',
    target: '2',
    // this will create the edge-type `custom`
    type: 'custom',
  },
  {
    id: 'e1-3',
    source: '1',
    target: '3',
    // this will create the edge-type `special`
    type: 'special',
  }
])
  
const nodes = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
  },
  {
    id: '2',
    label: 'Node 2',
    position: { x: 50, y: 250 },
  },
  {
    id: '3',
    label: 'Node 3',
    position: { x: 250, y: 50 },
  },
  {
    id: '4',
    label: 'Node 4',
    position: { x: 250, y: 250 },
  },
])
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <template #edge-custom="customEdgeProps">
      <CustomEdge v-bind="customEdgeProps" />
    </template>
    
    <template #edge-special="specialEdgeProps">
      <SpecialEdge v-bind="specialEdgeProps" />
    </template>
  </VueFlow>
</template>
vue
<script setup>
import { BezierEdge } from '@vue-flow/core';

// props were passed from the slot using `v-bind="customEdgeProps"`
const props = defineProps(['sourceX', 'sourceY', 'targetX', 'targetY', 'sourcePosition', 'targetPosition']);
</script>

<script lang="ts">
export default {
  name: 'CustomEdge',
};
</script>

<template>
  <BezierEdge
      :source-x="sourceX"
      :source-y="sourceY"
      :target-x="targetX"
      :target-y="targetY"
      :source-position="sourcePosition"
      :target-position="targetPosition"
  />
</template>
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { Edge } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core'

import CustomEdge from './CustomEdge.vue'
import SpecialEdge from './SpecialEdge.vue'

// You can pass 3 optional generic arguments to the Edge type, allowing you to define:
// 1. The data object type
// 2. The events object type
// 3. The possible edge types

interface CustomData {
    hello: string
}

type CustomEdgeTypes = 'custom' | 'special'

type CustomEdge = Edge<CustomData, any, CustomEdgeTypes>

export const edges = ref<CustomEdge[]>([
    {
      id: 'e1-2',
      source: '1',
      target: '2',
      // this will create the edge-type `custom`
      type: 'custom',
    },
    {
      id: 'e1-3',
      source: '1',
      target: '3',
      // this will create the edge-type `special`
      type: 'special',
    },
    
    {
      id: 'e1-4',
      source: '1',
      target: '4',
      // this will throw a type error, as the type is not defined in the CustomEdgeTypes
      // regardless it would be rendered as a default edge type
      type: 'not-defined',
    }
])
  
const nodes = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
  },
  {
    id: '2',
    label: 'Node 2',
    position: { x: 50, y: 250 },
  },
  {
    id: '3',
    label: 'Node 3',
    position: { x: 250, y: 50 },
  },
  {
    id: '4',
    label: 'Node 4',
    position: { x: 250, y: 250 },
  },
])  
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <template #edge-custom="customEdgeProps">
      <CustomEdge v-bind="customEdgeProps" />
    </template>
    
    <template #edge-special="specialEdgeProps">
      <SpecialEdge v-bind="specialEdgeProps" />
    </template>
  </VueFlow>
</template>
vue
<script setup lang="ts">
import type { EdgeProps } from '@vue-flow/core';
import { BezierEdge } from '@vue-flow/core';

import { CustomData } from './edges'

// props were passed from the slot using `v-bind="customEdgeProps"`
const props = defineProps<EdgeProps<CustomData>>();

console.log(props.data.hello) // 'world'
</script>

<script lang="ts">
export default {
  name: 'CustomEdge',
};
</script>

<template>
  <BezierEdge
      :source-x="sourceX"
      :source-y="sourceY"
      :target-x="targetX"
      :target-y="targetY"
      :source-position="sourcePosition"
      :target-position="targetPosition"
  />
</template>

Vue Flow will then attempt to resolve this edge-type to a component. Priority is given to a definition in the edgeTypes object of the state. Next, it tries to match the component to a globally registered one with the same name. Finally, it searches for a provided template slot to fill in the edge-type.

If no methods produce a result in resolving the component, the default edge-type is used as a fallback.

Template slots ​

One of the easiest ways to define custom edges is, by passing them as template slots. Dynamic resolution to slot-names is done for your user-defined edge-types, meaning a edge with the type custom is expected to have a slot named #edge-custom.

vue
<script setup>
import { VueFlow } from '@vue-flow/core'
import CustomEdge from './CustomEdge.vue'

const elements = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
  },
  {
    id: '2',
    label: 'Node 2',
    position: { x: 50, y: 250 },
  },
  {
    id: 'e1-2',
    type: 'custom',
    source: '1',
    target: '2',
  },
])
</script>
<template>
  <VueFlow v-model="elements">
    <template #edge-custom="props">
      <CustomEdge v-bind="props" />
    </template>
  </VueFlow>
</template>

Edge-types object ​

Alternatively, edge-types can also be defined by passing an object as a prop to the VueFlow component (or as an option to the composable).

WARNING

Take precaution to mark your components as raw (utilizing the marked function from the Vue library) to prevent their conversion into reactive objects. Otherwise, Vue will display a warning on the console.

vue
<script setup>
import { markRaw } from 'vue'
import CustomEdge from './CustomEdge.vue'

const edgeTypes = {
  custom: markRaw(CustomEdge),
}

const elements = ref([
  {
    id: '1',
    label: 'Node 1',
  },
  {
    id: '1',
    label: 'Node 1',
  },
    {
    id: 'e1-2',
    type: 'custom',
    source: '1',
    target: '2',
  },
])
</script>
<template>
  <div style="height: 300px">
    <VueFlow v-model="elements" :edge-types="edgeTypes" />
  </div>
</template>

Edge Props ​

Your custom edges are enclosed so that fundamental functions like selecting operate. But you may wish to expand on these features or implement your business logic inside edges, thus your edges receive the following properties:

Prop NameDescriptionTypeOptional
idUnique edge idstring
sourceNodeThe originating nodeGraphNode
targetNodeThe destination nodeGraphNode
sourceID of the source nodestring
targetID of the target nodestring
typeEdge Typestring
labelEdge label, can be a string or a VNodestring | VNode | Component | Object
styleCSS propertiesCSSProperties
selectedIs edge selectedboolean
sourcePositionSource positionPosition
targetPositionTarget positionPosition
sourceHandleIdID of the source handlestring
targetHandleIdID of the target handlestring
animatedIs edge animatedboolean
updatableIs edge updatableboolean
markerStartStart markerstring
markerEndEnd markerstring
curvatureThe curvature of the edgenumber
interactionWidthWidth of the interaction area for the edgenumber
dataAdditional data of edgeany object
eventsContextual and custom events of edgeEdgeEventsOn

Edge Events ​

Vue Flow provides two main ways of listening to edge events, either by using useVueFlow to bind listeners to the event handlers or by binding them to the <VueFlow> component.

vue
<script setup>
import { ref } from 'vue'  
import { VueFlow, useVueFlow } from '@vue-flow/core'

// useVueFlow provides access to the event handlers
const { 
  onEdgeClick,
  onEdgeDoubleClick,
  onEdgeContextMenu,
  onEdgeMouseEnter,
  onEdgeMouseLeave,
  onEdgeMouseMove,
  onEdgeUpdateStart,
  onEdgeUpdate,
  onEdgeUpdateEnd,
} = useVueFlow()
  
const elements = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
  },
  {
    id: '2',
    label: 'Node 2',
    position: { x: 50, y: 250 },
  },
  {
    id: 'e1-2',
    source: '1',
    target: '2',
  },
])
  
// bind listeners to the event handlers
onEdgeClick((event, edge) => {
  console.log('edge clicked', edge)
})

onEdgeDoubleClick((event, edge) => {
  console.log('edge double clicked', edge)
})

onEdgeContextMenu((event, edge) => {
  console.log('edge context menu', edge)
})
  
// ... and so on  
</script>

<template>
  <VueFlow v-model="elements" />
</template>
vue
<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

const elements = ref([
  {
    id: '1',
    label: 'Node 1',
    position: { x: 50, y: 50 },
  },
  {
    id: '2',
    label: 'Node 2',
    position: { x: 50, y: 250 },
  },
  {
    id: 'e1-2',
    source: '1',
    target: '2',
  },
])
</script>

<template>
  <!-- bind listeners to the event handlers -->
  <VueFlow
    v-model="elements"
    @edge-click="console.log('edge clicked', $event)"
    @edge-double-click="console.log('edge double clicked', $event)"
    @edge-context-menu="console.log('edge context menu', $event)"
    @edge-mouse-enter="console.log('edge mouse enter', $event)"
    @edge-mouse-leave="console.log('edge mouse leave', $event)"
    @edge-mouse-move="console.log('edge mouse move', $event)"
    @edge-update-start="console.log('edge update start', $event)"
    @edge-update="console.log('edge update', $event)"
    @edge-update-end="console.log('edge update end', $event)"
  />
</template>

Interact to see events in browser console

Customizing Appearance ​

TIP

To override the styles of the default theme, visit the Theming section.

Released under the MIT License.