Adding Interactivity
In the previous guide we built a flow with a couple
of nodes and an edge. Because we bound our nodes and edges with v-model, that flow is
already interactive: you can select, drag, and delete nodes and edges out of the box.
This is the biggest difference from React Flow and Svelte Flow. When you use
v-model:nodes / v-model:edges, Vue Flow manages the state for you: it applies
changes, like a node being dragged or an element being deleted, directly
to your arrays. We call this an uncontrolled flow.
Uncontrolled flow with v-model
Binding nodes and edges with v-model is all you need for a flow where users can
move, select, and remove elements:
<script setup lang="ts">
import type { Edge, Node } from '@xyflow/vue';
import { shallowRef } from 'vue';
import { Background, Controls, VueFlow } from '@xyflow/vue';
const nodes = shallowRef<Node[]>([
{ id: 'n1', position: { x: 0, y: 0 }, data: { label: 'Node 1' }, type: 'input' },
{ id: 'n2', position: { x: 100, y: 100 }, data: { label: 'Node 2' } },
]);
const edges = shallowRef<Edge[]>([]);
</script>
<template>
<VueFlow v-model:nodes="nodes" v-model:edges="edges" fit-view>
<Background />
<Controls />
</VueFlow>
</template>Vue Flow replaces the whole nodes / edges array when it applies a change, so a
shallowRef is enough,
and much cheaper than a deep ref for large flows.
Connecting nodes
One thing is not applied automatically: creating a new edge when the user drags from
one node’s handle to another. For that, listen to the @connect event and append the new
edge with the addEdge utility.
Import addEdge
import { addEdge } from '@xyflow/vue';Add a connect handler
addEdge takes the new Connection and the current
edges array, and returns a new array with the edge appended:
function onConnect(connection: Connection) {
edges.value = addEdge(connection, edges.value);
}Pass it to VueFlow
<VueFlow v-model:nodes="nodes" v-model:edges="edges" fit-view @connect="onConnect">
<Background />
<Controls />
</VueFlow>Connectable flow
Try dragging from one node’s handle to the other. The @connect handler fires and the new
edge is added. 🥳
Controlled flow
Sometimes you want full control over the state so you can validate, transform, or persist every
change yourself rather than letting Vue Flow apply it. To do that, drop v-model and pass
nodes and edges as one-way props, then handle the @nodes-change and @edges-change
events yourself — each one hands you a changeset that knows how to apply itself.
For most apps v-model is the simpler choice. Reach for a controlled flow only when you
need to inspect or intercept every change before it is applied.
Handle the change events
Each handler receives a changeset of changes. Call
applyTo with your current array and it returns the next one:
import type { Edge, EdgeChangeset, Node, NodeChangeset } from '@xyflow/vue';
import { addEdge } from '@xyflow/vue';
function onNodesChange(changes: NodeChangeset<Node>) {
nodes.value = changes.applyTo(nodes.value);
}
function onEdgesChange(changes: EdgeChangeset<Edge>) {
edges.value = changes.applyTo(edges.value);
}
function onConnect(connection: Connection) {
edges.value = addEdge(connection, edges.value);
}Pass them to VueFlow
<VueFlow
:nodes="nodes"
:edges="edges"
fit-view
@nodes-change="onNodesChange"
@edges-change="onEdgesChange"
@connect="onConnect"
>
<Background />
<Controls />
</VueFlow>Controlled flow
The result looks identical, but now every change passes through your handlers before it touches the arrays.
What you get
Whichever approach you choose, an interactive flow lets your users:
- select nodes and edges
- drag nodes around the canvas
- connect nodes by dragging from one handle to another
- draw a multi-selection box by holding
Shift— the defaultselectionKeyCode - add to a selection by holding
Meta/Control— the defaultmultiSelectionKeyCode - remove selected elements with
Backspace— the defaultdeleteKeyCode
If you want to jump straight into building your own application, we recommend checking out the Customization section.