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)
| Value | Behavior |
|---|---|
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.