Custom Node Templates

By default ApexTree renders each node's name inside a simple card. Supply a nodeTemplate function to render arbitrary HTML inside every node instead.

nodeTemplate basics

nodeTemplate receives the node's resolved content (the value at contentKey) and returns an HTML string. The HTML is rendered inside an SVG <foreignObject>.

const tree = new ApexTree(document.getElementById('chart'), {
  nodeWidth: 160,
  nodeHeight: 60,
  nodeTemplate: (content) => `
    <div style="display:flex;align-items:center;justify-content:center;
                height:100%;font-weight:600;">
      ${content}
    </div>
  `,
})
tree.render(data)

The content argument

content is whatever contentKey points at on the node. With the default contentKey: 'name', it is the node's name string. Point contentKey at a data object to pass a richer payload:

const data = {
  id: 'ceo',
  name: 'Alice',
  data: { name: 'Alice Johnson', title: 'CEO', avatar: '/alice.jpg' },
  children: [],
}

const tree = new ApexTree(el, {
  contentKey: 'data',   // content is now the data object
  nodeWidth: 220,
  nodeHeight: 84,
  nodeTemplate: (content) => `
    <div style="display:flex;align-items:center;gap:12px;padding:0 12px;height:100%;">
      <img src="${content.avatar}" style="width:40px;height:40px;border-radius:50%;" />
      <div style="display:flex;flex-direction:column;">
        <span style="font-weight:600;">${content.name}</span>
        <span style="font-size:12px;color:#64748B;">${content.title}</span>
      </div>
    </div>
  `,
})
tree.render(data)

The context argument

The second argument carries layout-level settings so templates can adapt without reading globals:

FieldTypeDescription
directionTreeDirectionThe tree's growth direction
cardImagePosition'left' | 'top'Where the built-in card places the avatar
nodeTemplate: (content, context) => {
  const stack = context.cardImagePosition === 'top' ? 'column' : 'row'
  return `
    <div style="display:flex;flex-direction:${stack};align-items:center;
                gap:8px;height:100%;justify-content:center;">
      <img src="${content.avatar}" style="width:36px;height:36px;border-radius:50%;" />
      <span style="font-weight:600;">${content.name}</span>
    </div>
  `
}

Safari foreignObject caveats

Because templates render inside a <foreignObject> under a scaled viewBox, certain CSS properties trigger a Safari paint bug where content collapses to the SVG origin. Avoid these on template elements:

  • position (relative / absolute / fixed / sticky)
  • opacity < 1
  • transform
  • filter
  • z-index
  • will-change
  • mix-blend-mode
  • isolation: isolate

Use flex/grid layout with DOM order and color-based dimming instead. ApexTree logs a one-time console.warn if a template trips this.

// Avoid:  <div style="position:relative;opacity:0.8;transform:scale(1.1)">
// Prefer: <div style="display:flex;color:#94A3B8">

Built-in org card (OrgNodeData)

Before writing a custom template, consider the built-in card. Point contentKey at an OrgNodeData object and ApexTree renders a professional card (avatar, name, title, subtitle, status chip, accent stripe) with no template code. See Data Format.

cardImagePosition controls where the built-in card places the avatar:

const tree = new ApexTree(el, {
  contentKey: 'data',
  cardImagePosition: 'top',   // avatar above the text ('left' by default)
  nodeWidth: 200,
  nodeHeight: 120,
})

Per-node templates via node options

A custom nodeTemplate set globally applies to every node. To vary a single node, override font, node, and tooltip options through that node's options field (see Data Format). For entirely different markup per node, branch inside the global template on the content.

React example

import { ApexTreeChart } from 'react-apextree'

const options = {
  contentKey: 'data',
  nodeWidth: 220,
  nodeHeight: 84,
  nodeTemplate: (content: any) => `
    <div style="display:flex;align-items:center;gap:12px;padding:0 12px;height:100%">
      <img src="${content.avatar}" style="width:40px;height:40px;border-radius:50%" />
      <div style="display:flex;flex-direction:column">
        <span style="font-weight:600">${content.name}</span>
        <span style="font-size:12px;color:#64748B">${content.title}</span>
      </div>
    </div>
  `,
}

export default function TemplatedTree() {
  return <ApexTreeChart data={data} options={options} />
}