Components / Organs

Anatomy tree

A searchable hierarchy for selecting structures and controlling what your viewer shows. Bring your own data and rendering engine.

Arrows navigate and expand. Enter selects. Space toggles visibility.

Your viewer state

Select a structure or change its visibility. These callbacks can drive your own viewer.

Selected: none

{}

Original, simplified example data. No patient data, models, or clinical validation.

Installation

In a project set up as in Installation, run:

bunx shadcn@4.22.1 add https://organui.com/r/anatomy-tree.json

Or by name: bunx shadcn@4.22.1 add @organui/anatomy-tree.

The source installs into your configured UI directory, along with shadcn's button, input, field and empty if you do not have them yet. It uses your existing theme tokens; it installs no global styles or 3D packages. Tested configurations are documented in the repository.

View registry item JSON

Usage

"use client"
import { useState } from "react"
import { AnatomyTree } from "@/components/ui/anatomy-tree"

const data = [{ id: "heart", label: "Heart", children: [
  { id: "lv", label: "Left ventricle" }
]}]

export function Panel() {
  const [selectedId, select] = useState<string | null>(null)
  const [visibility, show] = useState<Record<string, boolean>>({})
  return <AnatomyTree data={data}
    selectedId={selectedId} onSelectionChange={select}
    visibility={visibility} onVisibilityChange={show}
    defaultExpandedIds={["heart"]} />
}

Use globally unique, nonempty IDs that remain stable between renders. Duplicate IDs throw an error. Labels may repeat. Selection is controlled: Enter or a label click emits an ID; navigation never changes selection. Keep the selected ID in your own state and use it to highlight your viewer.

Visibility is controlled by a map of leaf IDs to booleans. Missing leaves are visible. Branches summarize their leaves as visible, hidden, or mixed. Space or the visibility button hides all descendants when all are visible; otherwise it shows them all. This includes descendants hidden by search or collapsed branches. Branch IDs in the map do not override their leaves.

Search matches labels without case sensitivity, showing matches and their ancestors. Matching branches do not automatically include nonmatching children. Search temporarily expands results and disables collapse; clearing it restores your previous expansion. Selection remains unchanged even when its row is filtered out.

Keyboard and data updates

Tab enters the search field, then the tree as one tab stop. Up/Down move between visible rows; Home/End move to the first/last row. Right expands a branch or enters its first child. Left collapses a branch or moves to its parent. Enter selects; Space changes visibility. Selection and checked visibility are exposed separately to assistive technology.

Data updates retain state by ID. If the focused row disappears, focus returns to a visible ancestor or the first row; an empty result returns focus to search. Removed selected IDs are not automatically cleared: reconcile controlled state in your application. Visibility callbacks remove IDs absent from the current dataset. New leaves default to visible. Expansion defaults apply only on mount; use a React key to reset the component.

When selectedId changes to a row that is not shown, for example after a pick in your 3D viewer, the tree expands its ancestors and scrolls the row into view within its scrolling container, without moving the page. Mark a grouping with selectable: false when it has no single structure to select: clicking or pressing Enter on it expands or collapses it instead. Give any node a color to show a matching swatch before its label.

Customize

Set label for the accessible tree name and search label, className for the outer container, and defaultExpandedIds for initial expansion. Edit the installed source for row styling. Semantic background, foreground, muted, accent, border, and ring tokens come from your theme. No theme values are overwritten.

Designed for small to medium in-memory trees. No virtualization, lazy loading, drag and drop, multiselection, or viewer implementation. Built on shadcn's Base UI components; compatibility with Radix-based presets is not claimed. Keyboard/browser checks do not replace a screen-reader usability audit.