Skip to main content
This example shows how to create custom edge components in Vue Flow. You’ll learn how to add interactive elements to edges, use custom labels, and create different edge types.

Live Demo

View the live demo on vueflow.dev.

Complete Example

<script lang="ts" setup>
import { VueFlow } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
import CustomEdge from './CustomEdge.vue'
import CustomEdge2 from './CustomEdge2.vue'
import { initialEdges, initialNodes } from './initial-elements'
</script>

<template>
  <VueFlow :edges="initialEdges" :nodes="initialNodes" fit-view-on-init snap-to-grid>
    <template #edge-custom="props">
      <CustomEdge v-bind="props" />
    </template>

    <template #edge-custom2="props">
      <CustomEdge2 v-bind="props" />
    </template>

    <MiniMap />
    <Controls />
    <Background />
  </VueFlow>
</template>

Key Concepts

Registering Custom Edges

Use the #edge-{type} template slot to register custom edge components:
<VueFlow :edges="edges" :nodes="nodes">
  <template #edge-custom="props">
    <CustomEdge v-bind="props" />
  </template>
</VueFlow>
The slot name must match the type property of your edge.

Edge Props

Custom edge components receive these props:
interface EdgeProps<T = any> {
  id: string
  type: string
  source: string
  target: string
  sourceX: number
  sourceY: number
  targetX: number
  targetY: number
  sourcePosition: Position
  targetPosition: Position
  data?: T
  markerStart?: string
  markerEnd?: string
  style?: CSSProperties
  label?: string | Component
  // ... and more
}

Built-in Edge Types

Vue Flow provides several built-in edge types:
Smooth curved edge (default type):
{ id: 'e1', source: '1', target: '2' }
// or explicitly
{ id: 'e1', source: '1', target: '2', type: 'default' }

Creating Custom Edges

Basic Custom Edge

A custom edge needs to render the path and optionally labels:
<script setup>
import { getBezierPath } from '@vue-flow/core'

const props = defineProps<EdgeProps>()

const path = computed(() => getBezierPath(props))
</script>

<template>
  <path 
    :id="id" 
    :style="style" 
    class="vue-flow__edge-path" 
    :d="path[0]" 
    :marker-end="markerEnd" 
  />
</template>

Path Helpers

Vue Flow provides helper functions for different path types:
import { 
  getBezierPath,
  getStraightPath,
  getStepPath,
  getSmoothStepPath 
} from '@vue-flow/core'

// Returns [pathString, labelX, labelY, offsetX, offsetY]
const [path, labelX, labelY] = getBezierPath({
  sourceX: props.sourceX,
  sourceY: props.sourceY,
  targetX: props.targetX,
  targetY: props.targetY,
  sourcePosition: props.sourcePosition,
  targetPosition: props.targetPosition,
})

Adding Interactive Elements

Use EdgeLabelRenderer to add interactive elements to edges:
<template>
  <path :d="path[0]" class="vue-flow__edge-path" />
  
  <EdgeLabelRenderer>
    <div
      :style="{
        position: 'absolute',
        transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,
        pointerEvents: 'all',
      }"
      class="nodrag nopan"
    >
      <button @click="removeEdges(id)">Delete</button>
    </div>
  </EdgeLabelRenderer>
</template>
The nodrag and nopan classes prevent the edge button from triggering drag or pan events.

Edge Styling

Inline Styles

const edges = ref([
  {
    id: 'e1',
    source: '1',
    target: '2',
    style: { 
      stroke: 'red',
      strokeWidth: 2 
    }
  }
])

Animated Edges

const edges = ref([
  {
    id: 'e1',
    source: '1',
    target: '2',
    animated: true
  }
])

Edge Labels

{
  id: 'e1',
  source: '1',
  target: '2',
  label: 'Edge Label'
}

Markers

Add arrow markers to edges:
import { MarkerType } from '@vue-flow/core'

const edges = ref([
  {
    id: 'e1',
    source: '1',
    target: '2',
    markerEnd: {
      type: MarkerType.ArrowClosed,
      width: 20,
      height: 20,
      color: '#FF0072'
    },
    markerStart: {
      type: MarkerType.Arrow
    }
  }
])
Available marker types:
  • MarkerType.Arrow
  • MarkerType.ArrowClosed

Edge Data

Pass custom data to edges:
const edges = ref([
  {
    id: 'e1',
    source: '1',
    target: '2',
    type: 'custom',
    data: {
      text: 'Custom data',
      onDelete: handleDelete
    }
  }
])
Access it in your component:
<script setup>
const props = defineProps<EdgeProps<{
  text: string
  onDelete: () => void
}>>()
</script>

<template>
  <div>{{ data.text }}</div>
  <button @click="data.onDelete">Delete</button>
</template>

TypeScript Support

import type { EdgeProps } from '@vue-flow/core'

interface CustomEdgeData {
  label: string
  count: number
}

interface CustomEdgeProps extends EdgeProps<CustomEdgeData> {
  data: CustomEdgeData
}

const props = defineProps<CustomEdgeProps>()

Best Practices

Always add inheritAttrs: false to custom edge components:
export default {
  inheritAttrs: false,
}

Next Steps

Custom Nodes

Create custom node components

Validation

Validate connections before creation

Edge API

Complete edge type reference

Edge Label Renderer

EdgeLabelRenderer documentation

Build docs developers (and LLMs) love