Vue ApexSankey

Installation

npm install vue-apexsankey apexsankey @svgdotjs/svg.js

Or with yarn:

yarn add vue-apexsankey apexsankey @svgdotjs/svg.js

Demo

View Demo Project created using Vue-ApexSankey

Loading ApexSankey

Important: You must load ApexSankey before using the Vue component. Choose one of the following methods:

Option 1: ES Module Import (Recommended)

Import ApexSankey at your app's entry point to register it globally:

// main.ts
import "apexsankey";
import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

Option 2: CDN Script Tags

Add the scripts to your index.html before your app bundle:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/apexsankey/apexsankey.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

Quick Start

<script setup lang="ts">
import ApexSankey from "vue-apexsankey";
import type { GraphData, SankeyOptions } from "vue-apexsankey";

const data: GraphData = {
  nodes: [
    { id: "oil", title: "Oil" },
    { id: "gas", title: "Natural Gas" },
    { id: "coal", title: "Coal" },
    { id: "fossil", title: "Fossil Fuels" },
    { id: "energy", title: "Energy" },
  ],
  edges: [
    { source: "oil", target: "fossil", value: 15 },
    { source: "gas", target: "fossil", value: 20 },
    { source: "coal", target: "fossil", value: 25 },
    { source: "fossil", target: "energy", value: 60 },
  ],
};

const options: Partial<SankeyOptions> = {
  width: 800,
  height: 600,
  nodeWidth: 20,
};
</script>

<template>
  <ApexSankey :data="data" :options="options" />
</template>

License Setup

If you have a commercial license, set it once at app initialization before rendering any charts:

// main.ts
import "apexsankey";
import { createApp } from "vue";
import { setApexSankeyLicense } from "vue-apexsankey";
import App from "./App.vue";

// set license before mounting app
setApexSankeyLicense("your-license-key-here");

createApp(App).mount("#app");

Using Template Refs

Access the underlying SankeyGraph instance via template refs:

<script setup lang="ts">
import { ref, onMounted } from "vue";
import ApexSankey from "vue-apexsankey";
import type { GraphData } from "vue-apexsankey";

const chartRef = ref<InstanceType<typeof ApexSankey> | null>(null);

const data: GraphData = {
  nodes: [
    { id: "a", title: "A" },
    { id: "b", title: "B" },
  ],
  edges: [{ source: "a", target: "b", value: 10 }],
};

onMounted(() => {
  if (chartRef.value?.graph) {
    console.log("Graph instance:", chartRef.value.graph);
    console.log("Max rank:", chartRef.value.graph.maxRank);
  }
});
</script>

<template>
  <ApexSankey ref="chartRef" :data="data" />
</template>

Reactivity

The component automatically updates when props change:

<script setup lang="ts">
import { ref } from "vue";
import ApexSankey from "vue-apexsankey";
import type { GraphData, SankeyOptions } from "vue-apexsankey";

const data = ref<GraphData>({
  nodes: [
    { id: "a", title: "A" },
    { id: "b", title: "B" },
  ],
  edges: [{ source: "a", target: "b", value: 10 }],
});

const options = ref<Partial<SankeyOptions>>({
  nodeWidth: 20,
});

function updateData() {
  // chart will automatically re-render
  data.value = {
    ...data.value,
    edges: [{ source: "a", target: "b", value: 50 }],
  };
}

function updateOptions() {
  // chart will recreate with new options
  options.value = {
    ...options.value,
    nodeWidth: 30,
  };
}
</script>

<template>
  <div>
    <ApexSankey :data="data" :options="options" />
    <button @click="updateData">Update Data</button>
    <button @click="updateOptions">Update Options</button>
  </div>
</template>

Props

PropTypeRequiredDescription
dataGraphDataYesSankey diagram data (nodes and edges)
options{'Partial<SankeyOptions>'}NoConfiguration options for the diagram

Data Format

Nodes

interface Node {
  id: string; // unique identifier
  title: string; // display label
  color?: string; // optional custom color
}

Edges

interface Edge {
  source: string; // source node id
  target: string; // target node id
  value: number; // edge weight/size
  type?: string; // optional grouping type
  color?: string; // optional custom color
}

Complete Data Structure

interface GraphData {
  nodes: Node[];
  edges: Edge[];
  options?: {
    order?: string[][][]; // custom node ordering
    alignLinkTypes?: boolean; // align links by type
  };
}

Options

OptionTypeDefaultDescription
widthnumber | string800Width of graph container
heightnumber | string800Height of graph container
canvasStylestring""CSS styles for canvas root container
spacingnumber100Spacing from top and left of graph container
nodeWidthnumber20Width of graph nodes
nodeBorderWidthnumber1Border width of nodes in pixels
nodeBorderColorstring""Border color of nodes
onNodeClick(node: Node) => voidundefinedCallback function for node click
edgeOpacitynumber0.4Opacity value for edges (0 to 1)
edgeGradientFillbooleantrueEnable gradient fill based on node colors
enableTooltipbooleanfalseEnable tooltip on hover
enableToolbarbooleanfalseEnable/disable graph toolbar
tooltipIdstring"sankey-tooltip-container"Tooltip HTML element id
tooltipTemplate(content) => stringdefault templateHTML template for tooltip
tooltipBorderColorstring"#BCBCBC"Border color of tooltip
tooltipBGColorstring"#FFFFFF"Background color of tooltip
fontSizestring"14px"Font size of node labels
fontFamilystring""Font family of node labels
fontWeightstring"400"Font weight of node labels
fontColorstring"#000000"Font color of node labels

Custom Node Ordering

You can specify custom node ordering using the order option in data:

<script setup lang="ts">
import ApexSankey from "vue-apexsankey";
import type { GraphData } from "vue-apexsankey";

const data: GraphData = {
  nodes: [
    { id: "a", title: "A" },
    { id: "b", title: "B" },
    { id: "c", title: "C" },
  ],
  edges: [
    { source: "a", target: "c", value: 1 },
    { source: "b", target: "c", value: 2 },
  ],
  options: {
    order: [
      [["a", "b"]], // first layer
      [["c"]], // second layer
    ],
  },
};
</script>

<template>
  <ApexSankey :data="data" />
</template>

Custom Tooltip

<script setup lang="ts">
import ApexSankey from "vue-apexsankey";
import type { GraphData, SankeyOptions } from "vue-apexsankey";

const data: GraphData = {
  nodes: [
    { id: "a", title: "A" },
    { id: "b", title: "B" },
  ],
  edges: [{ source: "a", target: "b", value: 10 }],
};

const options: Partial<SankeyOptions> = {
  enableTooltip: true,
  tooltipTemplate: ({ source, target, value }) => `
    <div style="padding: 8px;">
      <strong>${source.title}</strong> → <strong>${target.title}</strong>
      <br />
      Value: ${value}
    </div>
  `,
};
</script>

<template>
  <ApexSankey :data="data" :options="options" />
</template>

Using the Composable

For more control, you can use the useSankey composable directly:

<script setup lang="ts">
import { ref } from "vue";
import { useSankey } from "vue-apexsankey";
import type { GraphData, SankeyOptions } from "vue-apexsankey";

const containerRef = ref<HTMLElement | null>(null);

const data = ref<GraphData>({
  nodes: [
    { id: "a", title: "A" },
    { id: "b", title: "B" },
  ],
  edges: [{ source: "a", target: "b", value: 10 }],
});

const options = ref<Partial<SankeyOptions>>({
  nodeWidth: 20,
});

const { graph, isReady, render, destroy, recreate } = useSankey({
  containerRef,
  data,
  options,
});
</script>

<template>
  <div ref="containerRef" style="width: 800px; height: 600px;" />
</template>

TypeScript

All types are exported for use in your TypeScript projects:

import ApexSankey, {
  GraphData,
  Node,
  Edge,
  SankeyOptions,
  CommonOptions,
  NodeOptions,
  EdgeOptions,
  FontOptions,
  TooltipOptions,
  SankeyGraph,
} from "vue-apexsankey";

SSR Support

This component is SSR-safe. It renders an empty container on the server and only initializes the chart client-side after the component is mounted.