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.
<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>
<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.
<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.
<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.
<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:
<!-- 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>
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
<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.
<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>
<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>
<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>
<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
.
<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.
<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 Name | Description | Type | Optional |
---|---|---|---|
id | Unique edge id | string | |
sourceNode | The originating node | GraphNode | |
targetNode | The destination node | GraphNode | |
source | ID of the source node | string | |
target | ID of the target node | string | |
type | Edge Type | string | |
label | Edge label, can be a string or a VNode | string | VNode | Component | Object | |
style | CSS properties | CSSProperties | |
selected | Is edge selected | boolean | |
sourcePosition | Source position | Position | |
targetPosition | Target position | Position | |
sourceHandleId | ID of the source handle | string | |
targetHandleId | ID of the target handle | string | |
animated | Is edge animated | boolean | |
updatable | Is edge updatable | boolean | |
markerStart | Start marker | string | |
markerEnd | End marker | string | |
curvature | The curvature of the edge | number | |
interactionWidth | Width of the interaction area for the edge | number | |
data | Additional data of edge | any object | |
events | Contextual and custom events of edge | EdgeEventsOn |
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.
<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>
<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.