Clawscale

Tree

A Tree shows hierarchical data, such as folders of datasets. It holds no state: you pass the nodes and handle expansion and selection.

Usage#

import { Tree, type TreeNodeInfo } from "@clawscale/react";

Each node needs a unique id and a label. childNodes makes it expandable. More than one top-level node makes a tree with several roots.

Examples#

Dataset browser#

Keep the expanded ids and the selected id in state, and set isExpanded and isSelected from them. icon and secondaryLabel add context to each row.

  • Expand groupraw
  • Collapse groupcurated
    • orders_daily3.4M rows
    • revenue_by_region12K rows
import { Tree, type TreeNodeInfo } from "@clawscale/react";
import { useState } from "react";

const DATASETS: TreeNodeInfo[] = [
  {
    id: "raw",
    label: "raw",
    childNodes: [
      { id: "raw.events", label: "events", icon: "th", secondaryLabel: "1.2B rows" },
      { id: "raw.orders", label: "orders", icon: "th", secondaryLabel: "84M rows" },
    ],
  },
  {
    id: "curated",
    label: "curated",
    childNodes: [
      { id: "curated.orders_daily", label: "orders_daily", icon: "th", secondaryLabel: "3.4M rows" },
      { id: "curated.revenue_by_region", label: "revenue_by_region", icon: "th", secondaryLabel: "12K rows" },
    ],
  },
];

export default function TreeDatasets() {
  const [expanded, setExpanded] = useState<TreeNodeInfo["id"][]>(["curated"]);
  const [selected, setSelected] = useState<TreeNodeInfo["id"]>("curated.orders_daily");

  const withState = (nodes: TreeNodeInfo[]): TreeNodeInfo[] =>
    nodes.map((node) => ({
      ...node,
      icon: node.childNodes ? (expanded.includes(node.id) ? "folder-open" : "folder-close") : node.icon,
      isExpanded: expanded.includes(node.id),
      isSelected: node.id === selected,
      childNodes: node.childNodes && withState(node.childNodes),
    }));

  const toggle = ({ id }: TreeNodeInfo) =>
    setExpanded((current) => (current.includes(id) ? current.filter((item) => item !== id) : [...current, id]));

  return (
    <div style={{ maxWidth: 360, width: "100%" }}>
      <Tree
        contents={withState(DATASETS)}
        onNodeClick={(node) => setSelected(node.id)}
        onNodeCollapse={toggle}
        onNodeExpand={toggle}
      />
    </div>
  );
}

Props interface#

Every callback receives the node, its path and the mouse event. The path lists indexes from the root: [1, 0] is the first child of the second top-level node.

interface TreeProps extends Props@clawscale/react
PropsDescription
className
string
A space-delimited list of class names to pass along to a child element.
Inherited from Props
compact
boolean
Whether to use a compact appearance which reduces the visual padding around node content.
contentsrequired
ReadonlyArray<TreeNodeInfo<T>>
The data specifying the contents and appearance of the tree.
onNodeClick
TreeEventHandler<T>
Invoked when a node is clicked anywhere other than the caret for expanding/collapsing the node.
onNodeCollapse
TreeEventHandler<T>
Invoked when caret of an expanded node is clicked.
onNodeContextMenu
TreeEventHandler<T>
Invoked when a node is right-clicked or the context menu button is pressed on a focused node.
onNodeDoubleClick
TreeEventHandler<T>
Invoked when a node is double-clicked. Be careful when using this in combination with an onNodeClick (single-click) handler, as the way this behaves can vary between browsers. See http://stackoverflow.com/q/5497073/3124288
onNodeExpand
TreeEventHandler<T>
Invoked when the caret of a collapsed node is clicked.
onNodeMouseEnter
TreeEventHandler<T>
Invoked when the mouse is moved over a node.
onNodeMouseLeave
TreeEventHandler<T>
Invoked when the mouse is moved out of a node.
interface TreeNodeInfo@clawscale/react
PropsDescription
childNodes
Array<TreeNodeInfo<T>>
Child tree nodes of this node.
className
string
A space-delimited list of class names for this tree node element.
disabled
boolean
Whether this tree node is non-interactive. Enabling this prop will ignore mouse event handlers (in particular click, down, enter, leave).
hasCaret
boolean
Whether the caret to expand/collapse a node should be shown. If not specified, this will be true if the node has children and false otherwise.
icon
IconName | MaybeElement
The name of a Blueprint icon (or an icon element) to render next to the node's label.
idrequired
string | number
A unique identifier for the node.
isExpanded
boolean
isSelected
boolean = false
Whether this node is selected.
labelrequired
string | React.JSX.Element
The main label for the node.
nodeData
T
An optional custom user object to associate with the node. This property can then be used in the onClick, onContextMenu and onDoubleClick event handlers for doing custom logic per node.
secondaryLabel
string | MaybeElement
A secondary label/component that is displayed at the right side of the node.