Tree
The Tree component displays hierarchical data as an expandable list of folders and items. It supports single and multiple selection, drag-and-drop reordering, in-place renaming, a built-in filter bar, and per-node icons and styles. Node ids are used throughout the component to track selection, expanded state and events.
A node with a children array (even an empty one) is a folder. A node whose children is null or absent is a leaf. The Tree never saves changes for you. Renaming and expanding write back to items, but drag-and-drop only reorders the tree on screen and fires onMove, so persisting the new order (for example, to a database) is up to the view.
Properties
| Name | Description | Property Type |
|---|---|---|
| items | The tree's top-level nodes. Node ids must be unique across the whole tree, not just among siblings. Expanding or collapsing a folder writes that node's expanded flag here, and renaming a node writes its label. Drag-and-drop does not write here. A new items value with different nodes or order (for example, a re-query after persisting) replaces the on-screen order. See TreeNode Properties below. | array |
| selection | The ids of the selected nodes. Written by the component when the user selects, and writing it from a script selects those nodes (ids not in the tree are dropped). Holds at most one id unless interaction.multiSelect is on. | array |
| selectionData | The data of each selected node, in the same order as selection (null for nodes without data). Output only. | array |
| interaction | What the user is allowed to do with the tree. See Interaction Properties below. | object |
| filter | The built-in filter bar. See Filter Properties below. | object |
| appearance | Row sizing, expand arrows and row state styles. See Appearance Properties below. | object |
| style | Style applied to the tree's root container. | style |
TreeNode Properties
Each node in the items array (and within any node's children) supports the following properties.
| Name | Description | Property Type |
|---|---|---|
| id | Identifier for the node, unique across the whole tree. Used by selection, expanded and every event. Numbers are treated as their string form. A node without an id is given a generated one, and a duplicate id gets a suffix. | string or number |
| label | The text shown for the node. | string |
| icon | The icon shown before the label, after the expand arrow. A null icon or an empty path uses appearance.defaultNodeIcons. See Icon Properties below. | object |
| disabled | Greys the node out and stops it from being selected, dragged or dropped into. A disabled folder disables everything under it. | boolean |
| draggable | Set to false to pin this node in place. Has no effect unless interaction.dragEnabled is on. Default is true. | boolean |
| droppable | Set to false so nothing can be dropped into this folder. Ignored on leaf nodes. Default is true. | boolean |
| editable | Set to false to stop this node from being renamed. Has no effect unless interaction.editEnabled is on. Default is true. | boolean |
| expanded | Whether this folder is open. Written by the component when the user expands or collapses it. Set it from a binding or script to open or close the folder. Leave it out to keep whatever state the user left the folder in. Ignored on leaf nodes. | boolean |
| data | A freeform payload (object, array, string, number, boolean or null), such as a database key. Returned in selectionData and in event payloads. | any |
| style | A per-node style, layered on top of every appearance style. | style |
| children | The node's child nodes. An array makes the node a folder, and null makes it a leaf. An empty array still makes a folder, so nodes can be dropped into it, but it shows no expand arrow and keeps the closed folder icon until it has children. | array |
Example items array:
[
{
"id": "enterprise-1",
"label": "Kanoa Industries",
"expanded": true,
"data": { "assetId": 9 },
"children": [
{
"id": "site-1",
"label": "Adelaide Hills",
"data": { "assetId": 10 },
"children": [
{
"id": "line-1",
"label": "Line 1",
"data": { "assetId": 101 },
"children": null
},
{
"id": "line-2",
"label": "Line 2",
"disabled": true,
"data": { "assetId": 102 },
"children": null
}
]
}
]
}
]
Icon Properties
Used by a node's icon and by each entry in appearance.defaultIcons and appearance.defaultNodeIcons.
| Name | Description | Property Type |
|---|---|---|
| path | The icon path in library/name form, for example material/folder. Empty shows no icon. | string |
| color | The icon fill color. Empty inherits the text color. | color |
| style | Style applied to the icon's svg element. | style |
Interaction Properties
| Name | Description | Property Type |
|---|---|---|
| interactable | When false, nodes can't be selected or dragged. Folders can still be expanded and collapsed. Default is true. | boolean |
| branchNodeSelectable | When false, only leaf nodes can be selected. Clicking a folder does nothing beyond expanding it through its arrow. Default is true. | boolean |
| multiSelect | Allows selecting several nodes with Ctrl/Cmd-click and Shift-click. Default is false. | boolean |
| dragEnabled | Allows nodes to be dragged to reorder or re-parent them. Each drop fires onMove. Per-node draggable, droppable and disabled narrow this further. Default is false. | boolean |
| editEnabled | Allows renaming nodes in place. Press Enter on the focused node or double-click its label, then press Enter or click away to save, and Escape to cancel. Saving writes the node's label and fires onEdit. Per-node editable and disabled narrow this further. Default is false. | boolean |
Filter Properties
The filter narrows the tree to nodes whose label contains the filter text, plus their ancestors. Folders open automatically while filtering and return to their previous state when the filter is cleared. Dragging is turned off while the filter has text.
| Name | Description | Property Type |
|---|---|---|
| visible | Shows the built-in filter bar above the tree: the filter box and the buttons beside it. Hide it to drive filter.text from elsewhere, for example a Text Field. Default is false. | boolean |
| text | The current filter. Written by the built-in filter box as the user types. Set it from a binding or script to filter the tree. Empty shows every node. | string |
| caseSensitive | Match the label's case exactly. Default is false. | boolean |
| placeholder | Placeholder text in the built-in filter box. Default is Filter Items.... | string |
| clearSelectionButton | Shows a button beside the filter box that clears the selection and fires onSelect. Disabled while nothing is selected or the tree isn't interactable. Default is true. | boolean |
| expandButton | Shows a button beside the filter box that expands every folder, then collapses them all on the next click. Each folder it opens or closes writes its expanded flag and fires onToggle, as if it had been clicked. Default is true. | boolean |
| matchCount | The number of nodes whose label matches, across the whole tree. Ancestors shown only for context aren't counted. 0 when the filter is empty. Output only. | integer |
| style | Style applied to the built-in filter box. | style |
| containerStyle | Style applied to the filter bar, which holds the filter box and its buttons. | style |
Appearance Properties
| Name | Description | Property Type |
|---|---|---|
| rowHeight | The height of each row in pixels. Icons scale with it. Default is 24. | number |
| indent | The horizontal indent per tree level, in pixels. Default is 12. | number |
| showGuideLines | Draws guide lines from each open folder down through its contents, with a short stub to each leaf. Default is true. | boolean |
| defaultIcons | The expand/collapse arrow shown in front of every node, before the node's own icon. See appearance.defaultIcons below. | object |
| defaultNodeIcons | The node icon used when a node doesn't set its own icon path. See appearance.defaultNodeIcons below. | object |
| selectedStyle | Style for selected rows. Without it, selected rows use the theme's call-to-action blue with white text. Anything set here overrides that. | style |
| unselectedStyle | Style for rows that aren't selected. | style |
| hoverStyle | Style layered on a row while the mouse is over it. Not applied to disabled rows. | style |
| dropTargetStyle | Style layered on a folder while nodes are being dragged over it. | style |
| disabledStyle | Style layered on disabled rows, including everything under a disabled folder. | style |
appearance.defaultIcons
The expand/collapse arrow shown in front of every node. Leave a path empty to show nothing, while keeping the space so labels stay aligned. Each entry takes the Icon Properties above.
| Name | Description | Default Path |
|---|---|---|
| collapsed | The arrow for a closed folder. | material/arrow_right |
| expanded | The arrow for an open folder. | material/arrow_drop_down |
| empty | Shown in the arrow position for leaf nodes and folders with no children. | Empty |
appearance.defaultNodeIcons
The node icon used when a node doesn't set its own icon path. A node's own icon color and style still apply. Leave a path empty to show no icon. Each entry takes the Icon Properties above.
| Name | Description | Default Path |
|---|---|---|
| collapsed | The icon for a closed folder. | material/folder |
| expanded | The icon for an open folder. | material/folder_open |
| empty | The icon for a leaf node. | material/stop |
Component Events
onSelect
Triggered when the selection changes, including when the clear selection button is used.
| Property | Type | Description |
|---|---|---|
| event.selection | array | The ids of the selected nodes after this change, as strings. Mirrors the selection property. |
| event.selectionData | array | The data of each selected node, in the same order as selection. Mirrors the selectionData property. |
onToggle
Triggered when the user expands or collapses a folder.
| Property | Type | Description |
|---|---|---|
| event.id | string | The id of the folder. |
| event.expanded | boolean | true if the folder is now open, false if it was closed. |
| event.data | any | The folder's data, or null if it has none. |
onDoubleClick
Triggered when the user double-clicks a folder or an item. Folders still expand or collapse as well.
| Property | Type | Description |
|---|---|---|
| event.id | string | The id of the node that was double-clicked. |
| event.label | string | The label of the node that was double-clicked. |
| event.data | any | The node's data, or null if it has none. |
onEdit
Triggered when the user renames a node and saves the new label. Requires interaction.editEnabled.
| Property | Type | Description |
|---|---|---|
| event.id | string | The id of the renamed node. |
| event.label | string | The new label, already written to the node in items. |
| event.previousLabel | string | The label before the rename. |
| event.data | any | The node's data, or null if it has none. |
onMove
Triggered when the user drops one or more nodes. Requires interaction.dragEnabled. The tree reorders itself on screen, but items is not changed. Use this event to persist the move.
| Property | Type | Description |
|---|---|---|
| event.dragIds | array | The ids of the dropped nodes, in the order they now appear under the target parent. |
| event.dragNodes | array | The dropped nodes, one per id in dragIds. Each has id, label, data, and fromParentId, the id of the node's parent before the move (null if it was top-level). |
| event.parentId | string | The id of the folder the nodes were dropped into, or null for the top level. |
| event.parentData | any | The target folder's data, or null for the top level or a folder without data. |
| event.index | integer | The final position of the first dropped node among the target parent's children, counted after the move (0-based). |
| event.siblingIds | array | The target parent's full child order after the move. Writing each id's position as its sort order is enough to persist the move. |
Common Scripting
Persist a drag-and-drop move by saving the new sibling order. In this example, saveSortOrder is a function in your project:
# onMove event handler
for position, nodeId in enumerate(event.siblingIds):
saveSortOrder(nodeId, event.parentId, position)
Read the data of the selected node:
tree = self.getSibling("Tree")
if tree.props.selectionData:
assetId = tree.props.selectionData[0]["assetId"]