Search and Breadcrumbs

ApexTree includes a built-in search input and breadcrumb trail, plus a programmatic API for building your own search and navigation UI.

enableSearch shows a search input in the toolbar area. Typing filters nodes by their resolved label; matches are highlighted along with their path to the root. Pressing Enter centers the camera on the first match.

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

Keyboard shortcuts (when a11y.enabled is on): / focuses the search input, Esc clears it.

Built-in breadcrumb

enableBreadcrumb shows a breadcrumb trail above the chart. It updates on node click to show the path from root to the clicked node; clicking a segment re-centers the camera on that ancestor.

const tree = new ApexTree(el, {
  enableBreadcrumb: true,
})
tree.render(data)

Build your own search UI with the graph API:

MethodDescription
findNodesByQuery(query)Return node ids whose resolved label contains query (case-insensitive); empty query returns none
setSearchHighlight(matchIds)Highlight matches and their lineage to root; pass [] to clear
getNodeLabel(nodeId)Resolve a node's display label
centerOnNode(nodeId)Center the camera on a node at the current zoom
const graph = tree.render(data)

const input = document.getElementById('my-search')
input.addEventListener('input', () => {
  const matches = graph.findNodesByQuery(input.value)
  graph.setSearchHighlight(matches)
})

input.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    const matches = graph.findNodesByQuery(input.value)
    if (matches.length) graph.centerOnNode(matches[0])
  }
})

Custom breadcrumb

setBreadcrumbHandler(handler) registers a callback invoked with the clicked node id on every node click. Combine it with getNodeMap() to walk from the node up to the root and render your own trail:

const graph = tree.render(data)

graph.setBreadcrumbHandler((nodeId) => {
  if (!nodeId) return
  const map = graph.getNodeMap()

  // walk up to the root
  const path = []
  let current = nodeId
  while (current) {
    path.unshift(map[current].name)
    current = map[current].parent
  }

  document.getElementById('crumbs').textContent = path.join(' › ')
})

Pass null to setBreadcrumbHandler to unregister.

Building a jump-to-node picker

const graph = tree.render(data)

// populate a datalist with every node label
const map = graph.getNodeMap()
const list = document.getElementById('node-list')
Object.values(map).forEach((node) => {
  const opt = document.createElement('option')
  opt.value = node.name
  list.appendChild(opt)
})

document.getElementById('jump').addEventListener('change', (e) => {
  const matches = graph.findNodesByQuery(e.target.value)
  if (matches.length) {
    graph.setSearchHighlight(matches)
    graph.centerOnNode(matches[0])
  }
})

Localizing search and breadcrumb text

The search placeholder, aria-labels, match-count text, and breadcrumb label are all overridable via locale.messages. See Localization and RTL for the full TreeMessages reference.

const tree = new ApexTree(el, {
  enableSearch: true,
  enableBreadcrumb: true,
  locale: {
    messages: {
      searchPlaceholder: 'Rechercher…',
      searchMatchCount: (n) => `${n} résultat${n === 1 ? '' : 's'}`,
      breadcrumbAriaLabel: 'Chemin',
    },
  },
})

React example

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

export default function SearchableTree() {
  const ref = useRef<ApexTreeRef>(null)
  const [query, setQuery] = useState('')

  const runSearch = (q: string) => {
    setQuery(q)
    const graph = ref.current?.getGraph()
    if (!graph) return
    const matches = graph.findNodesByQuery?.(q) ?? []
    graph.setSearchHighlight?.(matches)
    if (q && matches.length) graph.centerOnNode?.(matches[0])
  }

  return (
    <div>
      <input
        value={query}
        onChange={(e) => runSearch(e.target.value)}
        placeholder="Search nodes…"
      />
      <ApexTreeChart
        ref={ref}
        data={data}
        options={{ enableBreadcrumb: true }}
      />
    </div>
  )
}