Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

PropertyTree

A recursive, data-driven nested tree on the Disclosure primitive — branch nodes disclose, leaf nodes optionally select, each row carrying a StatusPip and a trailing KPI.

Import

PropertyTree is a registry composite — you own the source after installing:

npx ploxum add property-tree
import { PropertyTree, type PropertyTreeNode } from "@/components/property-tree";

Depends on @roger-emerson/ploxum-primitives (Disclosure, StatusPip) and @roger-emerson/ploxum-utils (cn).

Usage

const nodes: PropertyTreeNode[] = [
  {
    id: "north",
    label: "North concourse",
    status: "warning",
    metric: "47/48",
    defaultOpen: true,
    children: [
      { id: "north-cam", label: "Cameras", status: "ok", metric: "24" },
      { id: "north-radio", label: "Radio comms", status: "warning", metric: "5/6" },
    ],
  },
  {
    id: "south",
    label: "South concourse",
    status: "ok",
    metric: "48/48",
    children: [{ id: "south-cam", label: "Cameras", status: "ok", metric: "24" }],
  },
];
 
<PropertyTree nodes={nodes} onSelect={(id) => openZoneDetail(id)} />;

Branch nodes (those with children) render as a Disclosure; leaf nodes render as a row. When onSelect is supplied, every leaf renders as a button with hover + focus-ring affordances. Indentation is 16px per depth level.

Props

PropertyTree

PropTypeDefaultDescription
nodesPropertyTreeNode[]Top-level tree nodes, in display order.
onSelect(id: string) => voidWhen provided, leaf rows render as buttons calling onSelect(id).
classNamestringMerged onto the root <div>.
refRef<HTMLDivElement>Forwarded to the root <div>.

PropertyTreeNode

FieldTypeDescription
idstringStable key; also the value passed to onSelect.
labelReactNodeRow label, truncates on overflow.
statusStatusPipStatus?"live" | "ok" | "warning" | "critical" | "offline" | "unknown". Renders a leading StatusPip.
metricReactNode?Trailing KPI — rendered monospace + tabular-nums. Static text only.
childrenPropertyTreeNode[]?Child nodes. Presence makes the node a disclosing branch.
defaultOpenboolean?Initial open state for a branch node.

Design rules

  • Status is always a StatusPip — shape + color, never hue alone. The pip carries the accessible status label.
  • A branch node's metric is the Disclosure trailing slot, which lives inside the toggle button — so the branch metric must stay static and non-interactive. Never place a control there.
  • Selection is leaf-only. Branch rows toggle disclosure; only leaves call onSelect. Don't expect a branch click to fire selection.
  • Metrics use monospace tabular numerals so counts align down the tree as they tick.

Storybook

Composites/PropertyTree ↗