Selection

ApexTree can track selected nodes. Selection is opt-in and supports single or multiple selection. Selected nodes get an aria-selected="true" attribute and a visible ring, and the selection is fully controllable from code.

Enabling selection

Set enableSelection to 'single' or 'multi':

const tree = new ApexTree(document.getElementById('chart'), {
  enableSelection: 'multi',
})
tree.render(data)
ValueBehavior
false (default)Selection disabled; nodes still receive focus and hover states
'single'Clicking a node selects it; selecting another replaces the previous
'multi'Clicking toggles a node in/out of the selection; any number can be selected

Reading the selection

getSelection() returns the selected node ids in insertion order. It returns an empty array when nothing is selected or selection is disabled:

const graph = tree.render(data)

const ids = graph.getSelection()
console.log('Selected:', ids)   // e.g. ['vp1', 'eng2']

Setting the selection

setSelection(ids) replaces the current selection programmatically. In 'single' mode, only the first id is applied:

graph.setSelection(['vp1', 'vp2'])   // select two nodes (multi mode)
graph.setSelection(['ceo'])          // single mode: selects ceo

Clearing the selection

graph.clearSelection()

Reacting to selection changes

onSelectionChange(listener) registers a callback invoked with the new id array whenever the selection changes — from clicks or from setSelection()/clearSelection(). Pass null to unregister:

graph.onSelectionChange((ids) => {
  document.getElementById('count').textContent = `${ids.length} selected`
  updateDetailPanel(ids)
})

Building a selection-driven panel

const tree = new ApexTree(el, {
  enableSelection: 'multi',
})
const graph = tree.render(data)

graph.onSelectionChange((ids) => {
  const map = graph.getNodeMap()
  const names = ids.map((id) => map[id].name)
  document.getElementById('panel').innerHTML = names.length
    ? `<strong>Selected:</strong> ${names.join(', ')}`
    : '<em>Nothing selected</em>'
})

// external "select all leaves" button
document.getElementById('select-leaves').onclick = () => {
  const map = graph.getNodeMap()
  const leafIds = Object.values(map)
    .filter((n) => n.children.length === 0)
    .map((n) => n.id)
  graph.setSelection(leafIds)
}

Selection vs click

onNodeClick (a chart option) fires on every node click regardless of selection. onSelectionChange fires only when the selection set changes. Use onNodeClick for navigation or drill-down, and onSelectionChange for tracking a persistent selection.

const tree = new ApexTree(el, {
  enableSelection: 'multi',
  onNodeClick: (node) => console.log('clicked', node),
})
const graph = tree.render(data)
graph.onSelectionChange((ids) => console.log('selection', ids))

Accessibility

With selection enabled, the root SVG gets aria-multiselectable="true" in 'multi' mode, and selected nodes carry aria-selected="true". Keyboard navigation (when a11y.enabled is on) lets users move focus and select via the keyboard. See Localization and RTL and the accessibility options in the Options reference.

React example

import { useRef, useState } from 'react'
import { ApexTreeChart } from 'react-apextree'
import type { ApexTreeRef } from 'react-apextree'

export default function SelectableTree() {
  const ref = useRef<ApexTreeRef>(null)
  const [selected, setSelected] = useState<string[]>([])

  const onLoad = () => {
    ref.current?.getGraph()   // ensures graph exists
    const graph = ref.current?.getGraph()
    graph?.onSelectionChange?.((ids: string[]) => setSelected(ids))
  }

  return (
    <div>
      <p>{selected.length} selected</p>
      <button onClick={() => ref.current?.getGraph()?.clearSelection?.()}>
        Clear
      </button>
      <ApexTreeChart
        ref={ref}
        data={data}
        options={{ enableSelection: 'multi' }}
      />
    </div>
  )
}

Note: onSelectionChange lives on the Graph instance (getGraph()), not on the ref handle directly.