Vue ApexTree

Installation

npm install vue-apextree apextree

Note: apextree is a peer dependency and must be installed alongside vue-apextree.

Demo

View Demo Project created using vue-apextree

Basic Usage

<script setup lang="ts">
import { ApexTreeChart, type NodeData } from 'vue-apextree';

const data: NodeData = {
  id: '1',
  name: 'CEO',
  children: [
    {
      id: '2',
      name: 'CTO',
      children: [
        { id: '3', name: 'Dev Lead' },
        { id: '4', name: 'QA Lead' },
      ],
    },
    {
      id: '5',
      name: 'CFO',
    },
  ],
};
</script>

<template>
  <ApexTreeChart
    :data="data"
    :width="800"
    :height="600"
    direction="top"
    :node-width="120"
    :node-height="80"
  />
</template>

Setting License Key

If you have a commercial license, set it once at app initialization:

// main.ts
import { setApexTreeLicense } from 'vue-apextree';

setApexTreeLicense('your-license-key');

Using Template Ref Methods

Access methods like changeLayout, collapse, expand, and fitScreen via template ref:

<script setup lang="ts">
import { ref } from 'vue';
import { ApexTreeChart, type ApexTreeExpose } from 'vue-apextree';

const treeRef = ref<ApexTreeExpose | null>(null);

const handleChangeLayout = () => {
  treeRef.value?.changeLayout('left');
};

const handleCollapse = (nodeId: string) => {
  treeRef.value?.collapse(nodeId);
};

const handleExpand = (nodeId: string) => {
  treeRef.value?.expand(nodeId);
};

const handleFitScreen = () => {
  treeRef.value?.fitScreen();
};
</script>

<template>
  <div>
    <button @click="handleChangeLayout">Change Layout</button>
    <button @click="handleFitScreen">Fit Screen</button>

    <ApexTreeChart
      ref="treeRef"
      :data="data"
      :width="800"
      :height="600"
    />
  </div>
</template>

Custom Node Templates

<script setup lang="ts">
import { ApexTreeChart } from 'vue-apextree';

interface PersonData {
  name: string;
  imageURL: string;
}

const nodeTemplate = (content: unknown): string => {
  const person = content as PersonData;
  return `
    <div style="display: flex; flex-direction: column; align-items: center; height: 100%;">
      <img 
        src="${person.imageURL}" 
        style="width: 50px; height: 50px; border-radius: 50%;" 
      />
      <div style="font-weight: bold;">${person.name}</div>
    </div>
  `;
};
</script>

<template>
  <ApexTreeChart
    :data="data"
    :width="800"
    :height="600"
    content-key="data"
    :node-width="150"
    :node-height="100"
    :node-template="nodeTemplate"
  />
</template>

Reactivity

A data change is reconciled into the live tree rather than rebuilding it: surviving nodes spring to their new positions, new ids grow in, departed ones retract, and collapse state, selection, focus and expanded cards all survive. A change to options rebuilds the instance, since options are read at construction.

The component watches data deeply, so mutating a nested array works as well as replacing the object:

<script setup lang="ts">
import { ref } from 'vue';
import { ApexTreeChart, type NodeData } from 'vue-apextree';

const data = ref<NodeData>({
  id: '1',
  name: 'Root',
  children: [],
});

// this will trigger a re-render
const addChild = () => {
  data.value.children?.push({
    id: String(Date.now()),
    name: 'New Node',
  });
};
</script>

<template>
  <button @click="addChild">Add Child</button>
  <ApexTreeChart :data="data" :width="800" :height="600" />
</template>

See Live Data Updates for why stable node ids matter to the diff.

Events

<script setup lang="ts">
import { ApexTreeChart, type NodeData } from 'vue-apextree';

const handleNodeClick = (node: NodeData) => {
  console.log('Node clicked:', node);
};
</script>

<template>
  <ApexTreeChart
    :data="data"
    :width="800"
    :height="600"
    @node-click="handleNodeClick"
  />
</template>

Props

PropTypeDefaultDescription
dataNodeDatarequiredTree data structure
widthnumber | string400Width of the container
heightnumber | string400Height of the container
direction'top' | 'bottom' | 'left' | 'right' | 'radial''top'Direction of tree growth
contentKeystring'name'Key for node content
siblingSpacingnumber50Spacing between siblings
childrenSpacingnumber50Spacing between parent and children
nodeWidthnumber50Width of nodes
nodeHeightnumber30Height of nodes
nodeTemplate(content: unknown) => string-Custom HTML template for nodes
nodeStylestring-CSS styles for nodes
nodeBGColorstring'#FFFFFF'Node background color
nodeBGColorHoverstring'#FFFFFF'Node background color on hover
borderWidthnumber1Node border width
borderStylestring'solid'Node border style
borderRadiusstring'5px'Node border radius
borderColorstring'#BCBCBC'Node border color
borderColorHoverstring'#5C6BC0'Node border color on hover
edgeWidthnumber1Edge line width
edgeColorstring'#BCBCBC'Edge line color
edgeColorHoverstring'#5C6BC0'Edge line color on hover
fontSizestring'14px'Font size
fontFamilystring-Font family
fontWeightstring'400'Font weight
fontColorstring'#000000'Font color
highlightOnHoverbooleantrueEnable highlight on hover
enableToolbarbooleanfalseShow toolbar
enableExpandCollapsebooleanfalseEnable expand/collapse buttons
enableTooltipbooleanfalseEnable tooltips
tooltipTemplate(content: unknown) => string-Custom tooltip template
groupLeafNodesbooleanfalseStack leaf nodes

Events

EventPayloadDescription
node-clickNodeDataEmitted when a node is clicked

Exposed Methods

MethodDescription
changeLayout(direction?)Change tree direction
collapse(nodeId)Collapse a node
expand(nodeId)Expand a node
expandAll()Expand every node in one reflow
collapseAll()Collapse every node, leaving the root visible
expandToDepth(depth)Show the tree down to a depth (root = 0)
updateData(data)Diff against a new dataset and spring to it
focus(nodeId)Spotlight a node's lineage and subtree
clearFocus()Remove the spotlight
setActivePath(nodeIds)Flow a marching dash along the root-to-node path
clearActivePath()Clear the active-path flow
toggleCard(nodeId)Toggle a node's expanded card
zoom(factor)Zoom by a fraction of the current scale (positive in, negative out)
centerOnNode(nodeId)Center the camera on a node
fitScreen()Fit tree to screen
getGraph()Get the underlying graph instance for the full API

getGraph() returns the core Graph, so anything not exposed here (expandSubtree, getExpandedCards, getActivePath, exportToSvg, selection and search) is reachable through it. See Methods.

Data Structure

interface NodeData<T = unknown> {
  id: string;           // unique identifier
  name?: string;        // display name (or use contentKey)
  data?: T;             // custom data for templates
  options?: NodeOptions; // per-node styling
  children?: NodeData<T>[];
}

interface NodeOptions {
  nodeBGColor?: string;
  nodeBGColorHover?: string;
  borderColor?: string;
  borderColorHover?: string;
  fontSize?: string;
  fontFamily?: string;
  fontWeight?: string | number;
  fontColor?: string;
}

TypeScript Support

Full TypeScript support with exported types:

import type {
  ApexTreeProps,
  ApexTreeExpose,
  NodeData,
  NodeOptions,
  TreeDirection,
  GraphInstance,
} from 'vue-apextree';