Devtools and Debugging
Vue Flow can feel like a black box, but you can reveal a lot about its internal state if you know where to look. This guide covers the built-in debugging aids, then shows how to build a few small inspectors of your own.
Built-in aids
-
The
debugprop. Setdebugon<VueFlow>and it logs each event to the console as it fires (high-frequency ones like move, drag, and hover are skipped), so you can see which events run.<VueFlow v-model:nodes="nodes" v-model:edges="edges" debug /> -
The
@errorevent. Vue Flow reports problems asVueFlowErrorinstances through the@errorevent — listen to it to log them or surface them to the user. -
Vue Devtools. Because nodes and edges are ordinary Vue components, the Vue Devtools browser extension lets you inspect the component tree, props, and reactive state of your flow like any other Vue app.
Build your own inspectors
Vue Flow doesn’t ship a devtools package, but its store is easy to read with useVueFlow(). The
example below adds three small inspectors — copy any of them into your own project, they each work
independently:
Viewport logger
The simplest thing to pull from the store is the viewport. useVueFlow().viewport is a
{ x, y, zoom } object derived from the pane transform; render it into a
<Panel>:
<script setup lang="ts">
import { Panel, useVueFlow } from '@xyflow/vue';
const { viewport } = useVueFlow();
</script>
<template>
<Panel position="bottom-right">
x: {{ viewport.x.toFixed(1) }} · y: {{ viewport.y.toFixed(1) }} · zoom: {{ viewport.zoom.toFixed(2) }}
</Panel>
</template>Change logger
Every change Vue Flow makes to your nodes flows through the onNodesChange hook. Subscribe to it
to log each batch as it’s dispatched — a great way to see what Vue Flow does under the hood:
<script setup lang="ts">
import { Panel, useVueFlow } from '@xyflow/vue';
import { shallowRef } from 'vue';
const { onNodesChange } = useVueFlow();
const log = shallowRef<string[]>([]);
onNodesChange((changes) => {
log.value = [changes.toArray().map(change => change.type).join(', '), ...log.value].slice(0, 6);
});
</script>
<template>
<Panel position="top-right">
<div v-for="(entry, index) in log" :key="index">{{ entry }}</div>
</Panel>
</template>See the NodeChange and
EdgeChange types for everything a change can be.
Node inspector
To render debug info that pans and zooms along with the flow, use the #zoom-pane slot — content
there lives inside the transformed viewport, so you can position it in flow coordinates. Here we
read every node with useVueFlow().getNodes and render its id and type above it:
<script setup lang="ts">
import { useVueFlow } from '@xyflow/vue';
const { getNodes } = useVueFlow();
</script>
<template>
<div
v-for="node in getNodes"
:key="node.id"
class="node-inspector"
:style="{ transform: `translate(${node.position.x}px, ${node.position.y - 56}px)` }"
>
<div>id: {{ node.id }}</div>
<div>type: {{ node.type ?? 'default' }}</div>
</div>
</template>Render it through the slot on <VueFlow>:
<template>
<VueFlow v-model:nodes="nodes" v-model:edges="edges">
<template #zoom-pane>
<NodeInspector />
</template>
</VueFlow>
</template>The #zoom-pane slot is Vue Flow’s way to render into the viewport: its content is positioned and
transformed along with the nodes and edges as the user pans and zooms.