Skip to content
D
Documentation

Vue quick start

tutorial
2 min readUpdated

Mount a Vue canvas with two connected nodes, keep its specs in typed refs, and capture the mounted instance through @init.

Framework bindings are thin skins over one headless model: specs describe your intent, live models hold the data, and the engine owns behavior.

Prerequisites

Use a browser-based Vue TypeScript project with single-file component support. This example assumes your project has an npm run dev script, as a Vite Vue project does.

The Vue binding's peer dependencies are Vue ^3.4.0, engine ^0.4.0, renderer ^0.5.0, and element ^0.5.0.

1. Install the binding and its peers

Run this in your project:

bash
npm install @grafloria/vue @grafloria/engine @grafloria/renderer vue @grafloria/element

You now have the Vue component and the shared engine and renderer packages it uses.

2. Mount a controlled canvas

Replace src/App.vue with this Vue single-file component, supplying GrafloriaFlow through refs typed with NodeSpec and EdgeSpec; see the React quick start for the shared canvas and endpoint setup.

v-model:nodes and v-model:edges supply the controlled props and write the component's emitted spec updates back into your refs. The init event supplies the mounted DiagramInstance. Keep it in a shallowRef and call fitView() to frame the content.

vue
<script setup lang="ts">
import { ref, shallowRef } from 'vue';
import {
  GrafloriaFlow,
  type NodeSpec,
  type EdgeSpec,
  type DiagramInstance,
} from '@grafloria/vue';

const nodes = ref<NodeSpec[]>([
  {
    id: 'a',
    position: { x: 60, y: 80 },
    size: { width: 180, height: 80 },
    label: 'Ingest',
  },
  {
    id: 'b',
    position: { x: 380, y: 80 },
    size: { width: 180, height: 80 },
    label: 'Publish',
  },
]);
const edges = ref<EdgeSpec[]>([
  { id: 'e1', source: 'a', target: 'b' },
]);
const instance = shallowRef<DiagramInstance | null>(null);

function onInit(api: DiagramInstance): void {
  instance.value = api;
  api.fitView();
}
</script>

<template>
  <p role="status">{{ instance ? 'Canvas ready' : 'Mounting canvas' }}</p>
  <div style="height: 400px">
    <GrafloriaFlow
      v-model:nodes="nodes"
      v-model:edges="edges"
      :plugins="true"
      @init="onInit"
    />
  </div>
</template>

You get an Ingest node connected to a Publish node. :plugins="true" adds the shipped minimap, zoom/fit controls, and background grid; the component loads these plugins lazily. No stylesheet import is needed.

Look for the arrow from Ingest to Publish, the zoom/fit controls at the lower left, and the minimap at the lower right.

For a self-contained canvas whose data the instance owns, use :default-nodes and :default-edges instead of the two v-model bindings. Those defaults seed the instance once at mount. For more on the return path and composables, see Vue: state and composables.

3. Open the editor

Start your project's development server and open the local URL it prints:

bash
npm run dev

Look for Canvas ready, the two labelled nodes, and their connecting edge. Drag a node to move it; use the canvas controls to zoom or fit the view. The Vue component disposes its instance and plugins when it unmounts—do not dispose the instance in onInit.

Explore the live Vue demos for running examples with Vue SFC source.

Replacing externally edited specs

Ordinary controlled updates reconcile into existing live objects rather than remounting the canvas. A full replacement with reused ids needs a different sequence.

Known issue: Replacing specs with reused node ids can retain old ports and metadata: the existing-node update path does not rebuild ports or remove omitted metadata. Until it is fixed, clear edges and nodes, await nextTick(), then apply the replacement.

The intended direct assignments are nodes.value = importedNodes and edges.value = importedEdges. For a fresh import, use this helper instead; pass the refs from your component and the imported spec arrays. It leaves the replacement diagram on the mounted canvas.

ts
import { nextTick, type Ref } from 'vue';
import type { NodeSpec, EdgeSpec } from '@grafloria/vue';

export async function replaceSpecs(
  nodes: Ref<NodeSpec[]>,
  edges: Ref<EdgeSpec[]>,
  importedNodes: NodeSpec[],
  importedEdges: EdgeSpec[],
): Promise<void> {
  edges.value = [];
  nodes.value = [];
  await nextTick();
  nodes.value = importedNodes;
  edges.value = importedEdges;
  await nextTick();
}

The first nextTick() lets the empty lists reconcile before you apply the replacement. Without that boundary, Vue batches the assignments and the watchers see only the final lists.

Where next

You now have a sized, controlled Vue canvas and access to its mounted instance.

Was this page helpful?