Skip to main content
This example demonstrates how to validate connections between nodes in Vue Flow. You can control which nodes can connect to each other using validation functions.

Live Demo

View the live demo on vueflow.dev.

Complete Example

<script lang="ts" setup>
import type { Connection, OnConnectStartParams } from '@vue-flow/core'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import CustomInput from './CustomInput.vue'
import CustomNode from './CustomNode.vue'

const { addEdges } = useVueFlow({
  nodes: [
    { 
      id: '0', 
      type: 'custominput', 
      position: { x: 0, y: 150 }, 
      isValidTargetPos: (connection) => connection.target === 'B' 
    },
    {
      id: 'A',
      type: 'customnode',
      position: { x: 250, y: 0 },
      isValidSourcePos: () => false,
    },
    { 
      id: 'B', 
      type: 'customnode', 
      position: { x: 250, y: 150 }, 
      isValidSourcePos: (connection) => connection.target === 'B' 
    },
    { 
      id: 'C', 
      type: 'customnode', 
      position: { x: 250, y: 300 }, 
      isValidSourcePos: (connection) => connection.target === 'B' 
    },
  ],
})

function onConnectStart({ nodeId, handleType }: OnConnectStartParams) {
  console.log('on connect start', { nodeId, handleType })
}

function onConnectEnd(event: MouseEvent) {
  console.log('on connect end', event)
}

function onConnect(params: Connection) {
  console.log('on connect', params)
  addEdges(params)
}
</script>

<template>
  <VueFlow
    :select-nodes-on-drag="false"
    class="validationflow"
    @connect="onConnect"
    @connect-start="onConnectStart"
    @connect-end="onConnectEnd"
  >
    <template #node-custominput="props">
      <CustomInput v-bind="props" />
    </template>
    <template #node-customnode="props">
      <CustomNode v-bind="props" />
    </template>
  </VueFlow>
</template>

Key Concepts

Validation Functions

Validation functions determine whether a connection is allowed. They receive a connection object and return a boolean:
type ValidConnectionFunc = (connection: Connection) => boolean

interface Connection {
  source: string
  target: string
  sourceHandle?: string | null
  targetHandle?: string | null
}

Node-Level Validation

Set validation on individual nodes:
const nodes = ref([
  {
    id: 'A',
    type: 'customnode',
    position: { x: 250, y: 0 },
    // This node cannot be a source
    isValidSourcePos: () => false,
  },
  {
    id: 'B',
    type: 'customnode',
    position: { x: 250, y: 150 },
    // This node can only connect to node 'B'
    isValidSourcePos: (connection) => connection.target === 'B',
  },
])

Handle-Level Validation

Pass validation to individual handles:
<Handle 
  type="source" 
  :position="Position.Right" 
  :is-valid-connection="isValidConnection" 
/>
function isValidConnection(connection: Connection) {
  // Only allow connections to node 'B'
  return connection.target === 'B'
}

Validation Types

Validates when this node is the source of a connection:
{
  id: '1',
  position: { x: 0, y: 0 },
  isValidSourcePos: (connection) => {
    // Allow connections only to node '2'
    return connection.target === '2'
  }
}

Connection Events

Listen to connection events to track connection attempts:
<VueFlow
  @connect="onConnect"
  @connect-start="onConnectStart"
  @connect-end="onConnectEnd"
>
  <!-- ... -->
</VueFlow>
function onConnectStart({ nodeId, handleType }: OnConnectStartParams) {
  console.log('User started connecting from:', nodeId, handleType)
}

function onConnectEnd(event: MouseEvent) {
  console.log('Connection attempt ended')
}

function onConnect(params: Connection) {
  console.log('Valid connection created:', params)
  addEdges(params)
}

Advanced Validation

Prevent Self-Connections

function isValidConnection(connection: Connection) {
  return connection.source !== connection.target
}

Validate by Node Type

const { findNode } = useVueFlow()

function isValidConnection(connection: Connection) {
  const sourceNode = findNode(connection.source)
  const targetNode = findNode(connection.target)
  
  // Only allow input nodes to connect to output nodes
  return sourceNode?.type === 'input' && targetNode?.type === 'output'
}

Limit Number of Connections

const { edges } = useVueFlow()

function isValidConnection(connection: Connection) {
  // Count existing connections from this source
  const existingConnections = edges.value.filter(
    (edge) => edge.source === connection.source
  )
  
  // Limit to 3 connections
  return existingConnections.length < 3
}

Validate Handle Connections

function isValidConnection(connection: Connection) {
  // Only allow connection from handle 'a' to handle 'b'
  return connection.sourceHandle === 'a' && connection.targetHandle === 'b'
}

Visual Feedback

Provide visual feedback for invalid connections using CSS:
/* Valid connection */
.vue-flow__edge.valid {
  stroke: green;
}

/* Invalid connection */
.vue-flow__edge.invalid {
  stroke: red;
}

/* Handle states */
.vue-flow__handle-valid {
  background: green;
}

.vue-flow__handle-connecting {
  background: blue;
}

Global Validation

Set validation for all connections:
const { onConnect } = useVueFlow({
  isValidConnection: (connection) => {
    // Global validation logic
    return connection.source !== connection.target
  }
})

onConnect((params) => {
  // This only runs if validation passes
  addEdges(params)
})

TypeScript Support

import type { ValidConnectionFunc, Connection } from '@vue-flow/core'

const isValidConnection: ValidConnectionFunc = (connection: Connection) => {
  return connection.target === 'allowedNode'
}

Best Practices

  • Combine node-level and handle-level validation for fine-grained control
  • Provide visual feedback when connections are invalid
  • Use TypeScript for type-safe validation functions
  • Consider performance when validating in large graphs

Example Use Cases

  1. Type-safe connections: Only allow certain node types to connect
  2. Direction enforcement: Enforce data flow direction (e.g., input → processing → output)
  3. Cycle prevention: Prevent circular dependencies
  4. Capacity limits: Limit the number of connections per node
  5. Handle matching: Ensure compatible handles connect (e.g., data types)

Next Steps

Custom Nodes

Create custom node components

Drag and Drop

Add nodes via drag and drop

Connection API

Connection type reference

Events

Learn about all available events

Build docs developers (and LLMs) love