Data Format

ApexTree renders from a single root NestedNode. Each node declares its id, display name, and an array of children. Children nest recursively to any depth.

NestedNode structure

const data = {
  id: 'ceo',
  name: 'Alice Johnson',
  children: [
    {
      id: 'cto',
      name: 'Bob Smith',
      children: [
        { id: 'eng1', name: 'Carol Lee', children: [] },
        { id: 'eng2', name: 'Dan Park', children: [] },
      ],
    },
    {
      id: 'cfo',
      name: 'Eve Torres',
      children: [],
    },
  ],
}

const tree = new ApexTree(document.getElementById('chart'), {})
tree.render(data)

Node fields

FieldTypeRequiredDescription
idstringYesUnique identifier, stable across renders
namestringYesDisplay label rendered inside the node
childrenNestedNode[]YesChild nodes; use [] for a leaf
dataTNoArbitrary payload attached to the node, available in callbacks
optionsobjectNoPer-node overrides for font, node, and tooltip options

Leaf nodes must still declare children: [].

contentKey

By default the node displays the value at the name key. Set contentKey in the chart options to point the label at a different field:

const data = {
  id: 'ceo',
  label: 'Alice Johnson',   // custom field
  children: [],
}

const tree = new ApexTree(el, {
  contentKey: 'label',   // read the label from 'label' instead of 'name'
})
tree.render(data)

contentKey can also point at a nested object — the built-in card template and OrgNodeData (below) rely on this.

Attaching custom data

Use the data field to carry arbitrary information. It is passed through to onNodeClick and is available on the resolved node map:

const data = {
  id: 'ceo',
  name: 'Alice',
  data: { email: 'alice@example.com', department: 'Executive' },
  children: [],
}

const tree = new ApexTree(el, {
  onNodeClick: (node) => {
    console.log(node.data.email)
  },
})
tree.render(data)

Per-node option overrides

Any node can override font, node, and tooltip options via its options field. These layer on top of the global chart options for that node only:

const data = {
  id: 'ceo',
  name: 'Alice',
  options: {
    nodeBGColor: '#EEF2FF',
    borderColor: '#6366F1',
    fontWeight: '700',
  },
  children: [
    {
      id: 'cto',
      name: 'Bob',
      options: {
        nodeBGColor: '#F0FDF4',
        borderColor: '#22C55E',
      },
      children: [],
    },
  ],
}

Per-node options accept the same keys as the font, node, and tooltip option groups.

Rich org-chart cards with OrgNodeData

For a professional org-chart card (avatar, name, title, subtitle, status chip, accent stripe), point contentKey at a data field holding an OrgNodeData object. The built-in node template understands its shape.

const data = {
  id: 'ceo',
  name: 'Alice Johnson',
  data: {
    name: 'Alice Johnson',
    title: 'Chief Executive Officer',
    subtitle: 'Executive Team',
    imageURL: '/avatars/alice.jpg',
    accentColor: '#6366F1',
    badge: { text: 'Active', color: '#22C55E' },
    meta: [
      { icon: 'bi bi-envelope', label: 'alice@example.com' },
      { icon: 'bi bi-geo-alt', label: 'San Francisco' },
    ],
  },
  children: [],
}

const tree = new ApexTree(el, {
  contentKey: 'data',   // read the card fields from the 'data' object
  nodeWidth: 240,
  nodeHeight: 100,
})
tree.render(data)

OrgNodeData fields

FieldTypeDescription
namestringPrimary display label (line 1)
titlestringJob title (line 2, medium, lower contrast)
subtitlestringDepartment or team (line 3, smaller)
imageURLstringAvatar URL, rendered as a circular image
accentColorstringColored left stripe on the card
badge{ text, color? }Status chip in the upper-right corner
meta{ icon?, label }[]Extra metadata rows (icon + label lines)

All fields are optional. Supplying only name renders a simple centered label, so existing simple trees are unaffected. icon is an optional CSS class for an icon font (e.g. Bootstrap Icons 'bi bi-person').

For fully custom rendering beyond OrgNodeData, use a custom node template.

TypeScript

NestedNode is generic over the data payload type:

import type { NestedNode } from 'apextree'

interface EmployeeData {
  email: string
  department: string
}

const data: NestedNode<EmployeeData> = {
  id: 'ceo',
  name: 'Alice',
  data: { email: 'alice@example.com', department: 'Executive' },
  children: [],
}