Mount a typed Grafloria flow in Vue 3, keep its nodes and edges in Vue state, and call the live diagram instance from your component.
Grafloria uses one headless model behind every framework binding: the Vue component converts your specs into the diagram model, while the live instance gives you the rendered diagram and its operations.
Prerequisites
- Vue 3.4 or later
- A Vite-based Vue application with TypeScript support
- Node.js 20.19 or later when your project loads the packages through Node
Install the packages
bashnpm install @grafloria/vue @grafloria/element @grafloria/renderer @grafloria/engine
1. Define typed graph data
Import NodeSpec and EdgeSpec, then keep the graph in refs. The node IDs in the edge endpoints must match the node IDs.
vue<script setup lang="ts"> import { ref } from 'vue'; import { GrafloriaFlow } from '@grafloria/vue'; import type { NodeSpec, EdgeSpec } from '@grafloria/vue'; const nodes = ref<NodeSpec[]>([ { id: 'ingest', position: { x: 60, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Ingest' }, }, { id: 'publish', position: { x: 380, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Publish' }, }, ]); const edges = ref<EdgeSpec[]>([ { id: 'ingest-to-publish', source: 'ingest', target: 'publish' }, ]); </script> <template> <div style="height: 100vh"> <GrafloriaFlow v-model:nodes="nodes" v-model:edges="edges" /> </div> </template>
The mounted flow draws two labelled boxes joined by a link. Dragging a node or adding and removing graph items updates the bound refs through v-model:nodes and v-model:edges. The wrapper has a resolved height, so the canvas has room to render.
For initial data that the canvas owns after mount, use :default-nodes="nodes" and :default-edges="edges" instead. Use the controlled v-model form when the rest of your application needs the graph data.
2. Add the built-in canvas controls
Set the plugins prop to true on the same mounted component:
vue<template> <div style="height: 100vh"> <GrafloriaFlow v-model:nodes="nodes" v-model:edges="edges" :plugins="true" /> </div> </template>
The canvas keeps the graph and adds the shipped minimap, zoom controls, fit control, and dotted background. No stylesheet import is required.
3. Capture the live instance
The init event supplies a DiagramInstance after the flow mounts. Keep that reference in the component, then call instance methods from your own UI.
vue<script setup lang="ts"> import { ref } from 'vue'; import { GrafloriaFlow } from '@grafloria/vue'; import type { DiagramInstance, EdgeSpec, NodeSpec } from '@grafloria/vue'; const nodes = ref<NodeSpec[]>([ { id: 'ingest', position: { x: 60, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Ingest' }, }, { id: 'publish', position: { x: 380, y: 80 }, size: { width: 180, height: 80 }, data: { label: 'Publish' }, }, ]); const edges = ref<EdgeSpec[]>([ { id: 'ingest-to-publish', source: 'ingest', target: 'publish' }, ]); let instance: DiagramInstance | null = null; function onInit(api: DiagramInstance): void { instance = api; } function fitDiagram(): void { instance?.fitView(); } </script> <template> <div style="height: 100vh"> <button type="button" @click="fitDiagram">Fit diagram</button> <GrafloriaFlow v-model:nodes="nodes" v-model:edges="edges" :plugins="true" @init="onInit" /> </div> </template>
The button calls fitView() on the mounted diagram and frames both nodes in the canvas. Before init fires, instance is null, so the optional call does nothing; after initialization it operates on the live diagram rather than on a separate model.
Use sibling UI and diagram specs
Use GrafloriaProvider when a toolbar or inspector is a sibling of the flow. The composables read the same mounted instance: useGrafloria returns it, useSelection returns reactive selection state, useViewport returns the camera, and useOnSelectionChange registers a selection callback. GrafloriaDiagram is the kit-spec host; GrafloriaCommentPanel displays the comment store when comments are enabled.
vue<script setup lang="ts"> import { computed, defineComponent, h } from 'vue'; import { GrafloriaCommentPanel, GrafloriaDiagram, GrafloriaFlow, GrafloriaProvider, useGrafloria, useOnSelectionChange, useSelection, useViewport, } from '@grafloria/vue'; const Toolbar = defineComponent({ setup() { const grafloria = useGrafloria(); const selection = useSelection(); const viewport = useViewport(); const commentStore = computed(() => grafloria.value?.getCommentStore() ?? null); useOnSelectionChange(() => { // Update application state here when the selection changes. }); return () => h('aside', [ h('p', `Selected: ${selection.value.nodes.length}; zoom: ${viewport.value.zoom}`), commentStore.value ? h(GrafloriaCommentPanel, { store: commentStore.value }) : null, ]); }, }); const nodes = [ { id: 'start', position: { x: 60, y: 80 }, data: { label: 'Start' } }, { id: 'finish', position: { x: 300, y: 80 }, data: { label: 'Finish' } }, ]; const edges = [{ id: 'start-to-finish', source: 'start', target: 'finish' }]; const spec = JSON.stringify({ nodes, edges }); </script> <template> <GrafloriaProvider> <div style="height: 500px"> <GrafloriaFlow :default-nodes="nodes" :default-edges="edges" :comments="true" /> <Toolbar /> </div> </GrafloriaProvider> <div style="height: 400px"> <GrafloriaDiagram :spec="spec" /> </div> </template>
The provider makes the flow instance available to sibling tools; the selection count and zoom value update as the user interacts with the flow. The comment panel receives the flow's store, while the second canvas renders the separate diagram spec.
What you have at the end
Your Vue component now renders a typed, editable two-node flow, keeps graph changes in Vue refs, and holds the live instance for operations such as fitView(), renderNow(), getModel(), and getEngine().
Try the Vue 3 in 10 minutes tutorial and its live Vue demos. Next, read How Grafloria works for the model and instance layers, or Customize nodes for Vue slot-defined nodes.
Was this page helpful?