Trees

General


Trees
Multiple-level structure list.

Show Code
import React from "react";
import Trees from "pocko-ui/Trees";
import "pocko-ui/Trees/index.css";
 
const treesData = [
  {
    title: "level_1",
    key: "level 1",
    active: false,
    child_count: 1,
    children: [
      {
        title: "level_1-1",
        key: "level 1-1",
        active: true,
        child_count: 1,
        children: [
          {
            title: "level_1-1-1",
            key: "level 1-1-1",
          },
          {
            title: "level_1-1-2",
            key: "level 1-1-2",
          },
        ],
      },
    ],
  },
  {
    title: "level_2",
    key: "level 2",
    active: false,
    child_count: 0,
  },
  {
    title: "level_3",
    key: "level 3",
    active: false,
    child_count: 0,
  },
];
 
return (
  <div className="mt-4">
    <Trees
      data={treesData}
      id="title"
      name="key"
      hasChildrenFn={(item: any) => {
        // You may replace child_count with your own indicator field.
        return (
          (item.child_count ?? 0) > 0 ||
          (Array.isArray(item.children) && item.children.length > 0)
        );
      }}
    ></Trees>
  </div>
);

Push some expansion buttons to each item of the tree

Show Code
import React from "react";
import Trees from "pocko-ui/Trees";
import "pocko-ui/Trees/index.css";
 
const treesData = [
  {
    title: "level_1",
    key: "level 1",
    active: false,
    child_count: 1,
    children: [
      {
        title: "level_1-1",
        key: "level 1-1",
        active: true,
        child_count: 1,
        children: [
          {
            title: "level_1-1-1",
            key: "level 1-1-1",
          },
          {
            title: "level_1-1-2",
            key: "level 1-1-2",
          },
        ],
      },
    ],
  },
  {
    title: "level_2",
    key: "level 2",
    active: false,
    child_count: 0,
  },
  {
    title: "level_3",
    key: "level 3",
    active: false,
    child_count: 0,
  },
];
 
const createCustomContent = (node: any) => (
  <div className="d-flex align-items-center gap-2 p-1 bg-body rounded">
    <i
      className="fa-solid fa-circle-plus text-info"
      onClick={() => {
        console.log(
          "You can add new node behind tree-node by your function",
          node
        );
      }}
    ></i>
 
    <i
      className="fa-solid fa-pen mx-2 text-warning"
      onClick={() => {
        console.log("You can edit this tree-node by your function", node);
      }}
    ></i>
 
    <i
      className="fa-regular fa-trash-can text-danger"
      onClick={() => {
        console.log("You can delete this tree-node by your function", node);
      }}
    ></i>
  </div>
);
 
return (
  <div className="mt-4">
    <Trees
      data={treesData}
      id="title"
      name="key"
      renderCustomContent={createCustomContent}
      wrapperClassName={"col-4"}
      hasChildrenFn={(item: any) => {
        // You may replace child_count with your own indicator field.
        return (
          (item.child_count ?? 0) > 0 ||
          (Array.isArray(item.children) && item.children.length > 0)
        );
      }}
    />
  </div>
 );

Using Another icon to Show Expand

Show Code
import React from "react";
import Trees from "pocko-ui/Trees";
import "pocko-ui/Trees/index.css";
 
const treesData = [
  {
    title: "level_1",
    key: "level 1",
    active: false,
    child_count: 1,
    children: [
      {
        title: "level_1-1",
        key: "level 1-1",
        active: true,
        child_count: 1,
        children: [
          {
            title: "level_1-1-1",
            key: "level 1-1-1",
          },
          {
            title: "level_1-1-2",
            key: "level 1-1-2",
          },
        ],
      },
    ],
  },
  {
    title: "level_2",
    key: "level 2",
    active: false,
    child_count: 0,
  },
  {
    title: "level_3",
    key: "level 3",
    active: false,
    child_count: 0,
  },
];
 
return (
  <div className="mt-4">
    <Trees
      data={treesData}
      id="title"
      name="key"
      wrapperClassName={"col-4"}
      hasChildrenFn={(item: any) => {
        // You may replace child_count with your own indicator field.
        return (
          (item.child_count ?? 0) > 0 ||
          (Array.isArray(item.children) && item.children.length > 0)
        );
      }}
      // The icon to display for nodes that do not have children
      leafIcon={
        <svg
          width="0.75em"
          height="0.75em"
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 512 512"
        >
          <path d="M313.4 32.9c26 5.2 42.9 30.5 37.7 56.5l-2.3 11.4c-5.3 26.7-15.1 52.1-28.8 75.2l144 0c26.5 0 48 21.5 48 48c0 18.5-10.5 34.6-25.9 42.6C497 275.4 504 288.9 504 304c0 23.4-16.8 42.9-38.9 47.1c4.4 7.3 6.9 15.8 6.9 24.9c0 21.3-13.9 39.4-33.1 45.6c.7 3.3 1.1 6.8 1.1 10.4c0 26.5-21.5 48-48 48l-97.5 0c-19 0-37.5-5.6-53.3-16.1l-38.5-25.7C176 420.4 160 390.4 160 358.3l0-38.3 0-48 0-24.9c0-29.2 13.3-56.7 36-75l7.4-5.9c26.5-21.2 44.6-51 51.2-84.2l2.3-11.4c5.2-26 30.5-42.9 56.5-37.7zM32 192l64 0c17.7 0 32 14.3 32 32l0 224c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32L0 224c0-17.7 14.3-32 32-32z" />
        </svg>
      }
      arrowIcons={[
        <svg
          width="0.75em"
          height="0.75em"
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 576 512"
        >
          <path d="M575.8 255.5c0 18-15 32.1-32 32.1l-32 0 .7 160.2c0 2.7-.2 5.4-.5 8.1l0 16.2c0 22.1-17.9 40-40 40l-16 0c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1L416 512l-24 0c-22.1 0-40-17.9-40-40l0-24 0-64c0-17.7-14.3-32-32-32l-64 0c-17.7 0-32 14.3-32 32l0 64 0 24c0 22.1-17.9 40-40 40l-24 0-31.9 0c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2l-16 0c-22.1 0-40-17.9-40-40l0-112c0-.9 0-1.9 .1-2.8l0-69.7-32 0c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z" />
        </svg>,
        <svg
          width="0.75em"
          height="0.75em"
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 448 512"
        >
          <path d="M224 0c-17.7 0-32 14.3-32 32l0 19.2C119 66 64 130.6 64 208l0 18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416l384 0c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8l0-18.8c0-77.4-55-142-128-156.8L256 32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3l-64 0-64 0c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z" />
        </svg>,
      ]}
    />
  </div>
);

Use the exposed method to expand or update the tree

Show Code
import React from "react";
import Trees from "pocko-ui/Trees";
import "pocko-ui/Trees/index.css";
 
const treesData = [
  {
    title: "level_1",
    key: "level 1",
    active: false,
    children: [
      {
        title: "level_1-1",
        key: "level 1-1",
        active: true,
        children: [
          {
            title: "level_1-1-1",
            key: "level 1-1-1",
            children: [],
          },
          {
            title: "level_1-1-2",
            key: "level 1-1-2",
            children: [],
          },
        ],
      },
    ],
  },
  {
    title: "level_2",
    key: "level 2",
    active: false,
    children: [],
  },
  {
    title: "level_3",
    key: "level 3",
    active: false,
    children: [],
  },
];
 
const treesRef = useRef();
 
const handleAdd = (node) => {
  // add node
  treesRef.current?.updatedTreeNode(node.title, {
    child_count: (node.child_count || 0) + 1,
    children: [
      ...node.children,
      {
        title: "level_add_add",
        key: "level add_add",
        children: [],
      },
    ],
  });
};
 
const handleDelete = (node) => {
  // delete node
  treesRef.current?.updatedTreeNode(node.title, "DELETE");
 
  // find parent node and update child_count
  const result = treesRef.current?.findNodeWithParentById(node.title);
  if (result?.parent) {
    const parent = result.parent;
    treesRef.current.updatedTreeNode(parent.title, {
      child_count: Math.max((parent.child_count ?? 1) - 1, 0),
    });
  }
};
 
const createCustomContent = (node) => (
  <div className="d-flex align-items-center gap-2 p-1 bg-body rounded">
    <i
      className="fa-solid fa-circle-plus text-info"
      onClick={() => handleAdd(node)}
    ></i>
 
    <i
      className="fa-regular fa-trash-can text-danger"
      onClick={() => handleDelete(node)}
    ></i>
  </div>
);
 
return (
  <div className="mt-4">
    <Trees
      treesRef={treesRef}
      data={treesData}
      id="title"
      name="key"
      wrapperClassName={"col-4"}
      renderCustomContent={createCustomContent}
      hasChildrenFn={(item) =>
        (item.child_count ?? 0) > 0 ||
        (Array.isArray(item.children) && item.children.length > 0)
      }
    />
  </div>
);

API


Trees
import Trees from "pocko-ui/Trees";
import "pocko-ui/Trees/index.css"
PropertyTypeDefaultDescriptionRequired
wrapperClassNamestring-The class name for the outer wrapper of the control.-
treesRefany-A reference to the component, which allows accessing and calling internal functions via useImperativeHandle.-
idstring-The field name in each node that uniquely identifies it.
namestring-The field name that holds the display label shown in the tree.
dataany[]-An array of data objects associated with the tree nodes.
defaultIdany-The ID of the default selected tree node.-
treeDataItemClickFunction-A callback function triggered when a tree node is clicked.-
renderCustomContentFunction-A function that renders custom content (such as buttons or additional information) for each tree node.-
dataServiceany-Add a service class as a parameter to interact with external data sources or APIs.-
dataServiceFunctionstring-The name of the function to be called from the service class.-
dataServiceFunctionParamsany[]-An array of parameters for the function call. Important: If the array contains $QUERY_STRING, the entered value will be treated as a parameter and passed out.-
leafIconReact.ReactNode-The icon to display for nodes that do not have children (i.e., leaf nodes). If not provided, no icon is shown.-
arrowIconsReact.ReactNode[]-An array containing one or two icons used to indicate node expand/collapse states. One icon will rotate; two icons toggle.-
hasChildrenFn(node: any) => boolean-A function used to determine whether a node has children. Should return true if the node is expandable.-

Ref Methods API


The Trees component exposes several methods via the treesRef prop using useImperativeHandle. These methods allow you to update or query the internal state of the tree externally.

Method NameParametersDescription
updatedTreeNode(id, value)id: string | number
value: object | 'DELETE'
Updates a specific node’s data, or removes the node if value is 'DELETE'.
findNodeWithParentById(id)id: string | numberRecursively finds the node and its direct parent. Returns { node, parent }.
getTreeData()(none)Returns the current full tree data (useful for snapshot or syncing).
Usage Example
const treesRef = useRef();
 
// ✅ Delete a node
treesRef.current?.updatedTreeNode(nodeId, 'DELETE');
 
// ✅ Update a node’s label and child count
treesRef.current?.updatedTreeNode(nodeId, {
  title: 'Renamed Node',
  child_count: 2,
});
 
// ✅ Find node and its parent
const result = treesRef.current?.findNodeWithParentById(nodeId);
if (result) {
  const { node, parent } = result;
  console.log('Node:', node, 'Parent:', parent);
}
 
// ✅ Get current tree data
const fullTree = treesRef.current?.getTreeData();