Tree

The Tree component is a virtualized tree component that displays hierarchical data with support for flat and hierarchy data formats.
Key features:
  • Flat and hierarchical data structures: You can select the most convenient data format to represent the tree. A set of properties enables you to map your data structure to the visual representation of the tree.
  • Flexible expand/collapse: You have several properties to represent the expanded and collapsed state of tree nodes. You can also specify several options that determine which tree items are collapsed initially.
  • Tree API: Several exposed methods allow you to manage the tree's view state imperatively.

Specifying Data

With the dataFormat property, you can select between "flat" or "hierarchy" formats. The component transforms the data according to the value of this property into a visual representation.
The "flat" and "hierarchy" data structures both use these fields for a particular tree node:
  • id: Unique ID of tree node
  • name: The field to be used as the display label
  • icon: An optional icon identifier. If specified, this icon is displayed with the tree item.
  • iconExpanded: An optional icon identifier. This icon is displayed when the field is expanded.
  • iconCollapsed: An optional icon identifier. This icon is displayed when the field is collapsed.
  • selectable: Indicates if the node can be selected.
The "flat" structure refers to its direct parent node via the parentId property, which contains the ID of the node it is referring to.
The "hierarchy" structure uses a children property, which is an array of nested child nodes (using the common node property set above).
This example demonstrates the use of the "flat" data mode:
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="all"
    data='{[
      { id: 1, icon:"folder", name: "Root Item 1", parentId: null },
      { id: 2, icon:"folder", name: "Child Item 1.1", parentId: 1 },
      { id: 3, icon: "code", name: "Child Item 1.2", parentId: 1 },
      { id: 4, icon: "code", name: "Grandchild Item 1.1.1", parentId: 2 },
    ]}'>
  </Tree>
</App>
Example: flat data format
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="all"
    data='{[
      { id: 1, icon:"folder", name: "Root Item 1", parentId: null },
      { id: 2, icon:"folder", name: "Child Item 1.1", parentId: 1 },
      { id: 3, icon: "code", name: "Child Item 1.2", parentId: 1 },
      { id: 4, icon: "code", name: "Grandchild Item 1.1.1", parentId: 2 },
    ]}'>
  </Tree>
</App>
This example demonstrates the use of the "hiearchy" data mode:
<App>
  <Tree
    testId="tree"
    dataFormat="hierarchy"
    defaultExpanded="all"
    data='{[
      {
        id: 1, icon: "folder", name: "Root Item 1",
        children: [
          { id: 2, icon: "code", name: "Child Item 1.1" },
          { id: 3, icon: "folder", name: "Child Item 1.2",
            children: [
              { id: 4, icon: "code", name: "Grandchild Item 1.2.1"}
            ],
          }
        ],
      },
    ]}'>
  </Tree>
</App>
Example: hierarchical data format
<App>
  <Tree
    testId="tree"
    dataFormat="hierarchy"
    defaultExpanded="all"
    data='{[
      {
        id: 1, icon: "folder", name: "Root Item 1",
        children: [
          { id: 2, icon: "code", name: "Child Item 1.1" },
          { id: 3, icon: "folder", name: "Child Item 1.2",
            children: [
              { id: 4, icon: "code", name: "Grandchild Item 1.2.1"}
            ],
          }
        ],
      },
    ]}'>
  </Tree>
</App>
When you use data (for example, retrieved from a backend), those structures may use different property names. The Tree component allows mapping data field names through these properties:
  • idField (default: id)
  • nameField (default: name)
  • iconField (default: icon)
  • iconExpandedField (default: iconExpanded)
  • iconCollapsedField (default: iconCollapsed)
  • parentIdField (default: parentId)
  • childrenField (default: children)
  • selectableField (default: selectable)
The following example uses the idField, nameField, and parentIdField mapping properties:
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="all"
    idField="uid"
    nameField="label"
    parentIdField="parent"
    data='{[
      { uid: 1, icon:"folder", label: "Root Item 1", parent: null },
      { uid: 2, icon:"folder", label: "Child Item 1.1", parent: 1 },
      { uid: 3, icon: "code", label: "Child Item 1.2", parent: 1 },
      { uid: 4, icon: "code", label: "Grandchild Item 1.1.1", parent: 2 },
    ]}'>
  </Tree>
</App>
Example: mapping data fields
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="all"
    idField="uid"
    nameField="label"
    parentIdField="parent"
    data='{[
      { uid: 1, icon:"folder", label: "Root Item 1", parent: null },
      { uid: 2, icon:"folder", label: "Child Item 1.1", parent: 1 },
      { uid: 3, icon: "code", label: "Child Item 1.2", parent: 1 },
      { uid: 4, icon: "code", label: "Grandchild Item 1.1.1", parent: 2 },
    ]}'>
  </Tree>
</App>

Expanding and collapsing tree nodes

By default, when you click a tree node outside of its expand/collapse icon, the specified item is selected. With the expandOnItemClick property (using the true value), you can change this behavior to expand or collapse the item when clicking its surface anywhere.
You can use the defaultExpanded property to specify what nodes you want to see expanded initially. You can set this property to a list of node IDs or a string. When you specify IDs, the component expands the hierarchy to reveal the specified nodes. When the value is a string, you can use these options:
  • none: all nodes are collapsed (default)
  • first-level: all first-level nodes are expanded
  • all: all nodes are expanded
The following example demonstrates the use of defaultExpanded with tree node IDs:
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="{['doc-root', 'proj-web', 'media-profile-pic']}"
    data='{[
      // Branch A: Documents
      { id: "doc-root", name: "[Documents]", parentId: null },
      { id: "doc-reports", name: "Reports", parentId: "doc-root" },
      { id: "doc-invoices", name: "Invoices", parentId: "doc-root" },
      { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
      { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
      { id: "doc-inv-001", name: "Invoice-001.pdf", parentId: "doc-invoices" },

      // Branch B: Projects
      { id: "proj-root", name: "Projects", parentId: null },
      { id: "proj-web", name: "[Web Apps]", parentId: "proj-root" },
      { id: "proj-mobile", name: "Mobile Apps", parentId: "proj-root" },
      { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
      { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
      { id: "proj-ios-app", name: "iOS Shopping App", parentId: "proj-mobile" },

      // Branch C: Media
      { id: "media-root", name: "Media", parentId: null },
      { id: "media-images", name: "Images", parentId: "media-root" },
      { id: "media-videos", name: "Videos", parentId: "media-root" },
      { id: "media-profile-pic", name: "[profile.jpg]", parentId: "media-images" },
      { id: "media-banner", name: "banner.png", parentId: "media-images" },
    ]}'>
  </Tree>
</App>
Example: defaultExpanded with node IDs
<App>
  <Tree
    testId="tree"
    dataFormat="flat"
    defaultExpanded="{['doc-root', 'proj-web', 'media-profile-pic']}"
    data='{[
      // Branch A: Documents
      { id: "doc-root", name: "[Documents]", parentId: null },
      { id: "doc-reports", name: "Reports", parentId: "doc-root" },
      { id: "doc-invoices", name: "Invoices", parentId: "doc-root" },
      { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
      { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
      { id: "doc-inv-001", name: "Invoice-001.pdf", parentId: "doc-invoices" },

      // Branch B: Projects
      { id: "proj-root", name: "Projects", parentId: null },
      { id: "proj-web", name: "[Web Apps]", parentId: "proj-root" },
      { id: "proj-mobile", name: "Mobile Apps", parentId: "proj-root" },
      { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
      { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
      { id: "proj-ios-app", name: "iOS Shopping App", parentId: "proj-mobile" },

      // Branch C: Media
      { id: "media-root", name: "Media", parentId: null },
      { id: "media-images", name: "Images", parentId: "media-root" },
      { id: "media-videos", name: "Videos", parentId: "media-root" },
      { id: "media-profile-pic", name: "[profile.jpg]", parentId: "media-images" },
      { id: "media-banner", name: "banner.png", parentId: "media-images" },
    ]}'>
  </Tree>
</App>
You have several options to style the icons representing the expanded or collapsed state:
  • The icons used for the expanded and collapsed states can be changed with the iconExpanded and iconCollapsed properties, respectively.
  • You can specify a different size with the iconSize property (using only numeric values considered as pixels)
  • Using a rotate animation when changing the state with the animateExpand flag. The following option demonstrates the last two options:
<App>
  <Tree
    testId="tree"
    iconSize="24"
    animateExpand
    dataFormat="flat"
    defaultExpanded="all"
    data='{[
      { id: 1, name: "Root Item 1", parentId: null },
      { id: 2, name: "Child Item 1.1", parentId: 1 },
      { id: 3, name: "Child Item 1.2", parentId: 1 },
      { id: 4, name: "Grandchild Item 1.1.1", parentId: 2 },
    ]}'>
  </Tree>
</App>
Example: expand/collapse options
<App>
  <Tree
    testId="tree"
    iconSize="24"
    animateExpand
    dataFormat="flat"
    defaultExpanded="all"
    data='{[
      { id: 1, name: "Root Item 1", parentId: null },
      { id: 2, name: "Child Item 1.1", parentId: 1 },
      { id: 3, name: "Child Item 1.2", parentId: 1 },
      { id: 4, name: "Grandchild Item 1.1.1", parentId: 2 },
    ]}'>
  </Tree>
</App>

Selection

Each tree node is selectable by default, unless the node item's data does not have a selectable property (or the one specified in selectedField). A selectable item can be selected by clicking the mouse or pressing the Enter or Space keys when it has focus.
You can set the selectedValue property to define the selected tree item, ot use the selectNode exposed method for imperative selection.

Item templates

You can override the default template used to display a tree item with the itemTemplate property. The template definition can use the $item context variable to access the item's attributes for display. $item provides these properties:
  • id: The unique node ID
  • name: The name of the node
  • depth: The depth level in the tree
  • isExpanded: Indicates if the tree node is expanded
  • hasChildren: Indicates if the tree node has children
  • children: The children of the tree node
  • selectable: Indicates if the node can be selected
  • parentId: The ID of the node's parent
  • parentIds: A list of parent IDs from the root node to the direct parent of the node
  • path: An array with the node names following the path from the root node to the displayed node.
  • loadingState: The current state of a dynamic node ("unloaded", "loading", or "loaded")
This example demonstrates these concepts:
<App>
  <Tree
    testId="tree"
    id="tree"
    defaultExpanded="all"
    data='{[
        { id: "root", name: "My Files", parentId: null },
        { id: "doc-root", name: "Documents", parentId: "root" },
        { id: "doc-reports", name: "Reports", parentId: "doc-root" },
        { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
        { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
        { id: "proj-root", name: "Projects", parentId: "root" },
        { id: "proj-web", name: "Web Apps", parentId: "proj-root" },
        { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
        { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
        { id: "media-root", name: "Media", parentId: "root" },
        { id: "media-images", name: "Images", parentId: "media-root" },
        { id: "media-videos", name: "Videos", parentId: "media-root" },
      ]}'>
    <property name="itemTemplate">
      <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
        <Icon name="{$item.hasChildren ? 'folder' : 'code'}" />
        <Text>
          ({$item.id}):
        </Text>
        <Text variant="strong">
          {$item.name}
        </Text>
      </HStack>
    </property>
  </Tree>
</App>
Example: itemTemplate
<App>
  <Tree
    testId="tree"
    id="tree"
    defaultExpanded="all"
    data='{[
        { id: "root", name: "My Files", parentId: null },
        { id: "doc-root", name: "Documents", parentId: "root" },
        { id: "doc-reports", name: "Reports", parentId: "doc-root" },
        { id: "doc-q1-report", name: "Q1 Report.pdf", parentId: "doc-reports" },
        { id: "doc-q2-report", name: "Q2 Report.pdf", parentId: "doc-reports" },
        { id: "proj-root", name: "Projects", parentId: "root" },
        { id: "proj-web", name: "Web Apps", parentId: "proj-root" },
        { id: "proj-ecommerce", name: "E-commerce Site", parentId: "proj-web" },
        { id: "proj-dashboard", name: "Admin Dashboard", parentId: "proj-web" },
        { id: "media-root", name: "Media", parentId: "root" },
        { id: "media-images", name: "Images", parentId: "media-root" },
        { id: "media-videos", name: "Videos", parentId: "media-root" },
      ]}'>
    <property name="itemTemplate">
      <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
        <Icon name="{$item.hasChildren ? 'folder' : 'code'}" />
        <Text>
          ({$item.id}):
        </Text>
        <Text variant="strong">
          {$item.name}
        </Text>
      </HStack>
    </property>
  </Tree>
</App>

Dynamic tree nodes

When initializing the tree with its data property, you can set the dynamic property of the node to true (you can use a field name alias with the dynamicField property). When you extend a dynamic node, the tree fires the loadChildren event, and the nodes returned by the event handler will be the actual nodes.
By default, nodes are not dynamic.
While the child nodes are being queried, the tree node displays a spinner to indicate the loading state.
You can use the markNodeUnloaded exposed method to reset the state of an already loaded dynamic tree node. The next time the user expands the node, its content will be loaded again.
The following sample demonstrates this feature. Click the "Child Item 1.2" node to check how it loads its children. Click the Unload button to reload the items when the node is expanded the next time.
<App var.loadCount="{0}">
  <Tree
    testId="tree"
    defaultExpanded="all"
    id="tree"
    itemClickExpands
    data='{[
      { id: 1, name: "Root Item 1", parentId: null },
      { id: 2, name: "Child Item 1.1", parentId: 1 },
      { id: 3, name: "Child Item 1.2", parentId: 1, dynamic: true },
      { id: 4, name: "Child Item 1.3", parentId: 1 },
    ]}'
    onLoadChildren="(node) => {
      loadCount++;
      delay(1000); 
      return ([
        { id: 5, name: `Dynamic Item 1.2.1 (${loadCount})` },
        { id: 6, name: `Dynamic Item 2.2.2 (${loadCount})` },
      ])
    }"
    >
    <property name="itemTemplate">
      <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
        <Icon name="{$item.hasChildren 
          ? ($item.loadingState === 'loaded' ? 'folder' : 'folder-outline' ) 
          : 'code'}" 
        />
        <Text>{$item.name}</Text>
      </HStack>
    </property>
  </Tree>
  <Button onClick="tree.markNodeUnloaded(3)">Unload</Button>
</App>
Example: dynamic nodes
<App var.loadCount="{0}">
  <Tree
    testId="tree"
    defaultExpanded="all"
    id="tree"
    itemClickExpands
    data='{[
      { id: 1, name: "Root Item 1", parentId: null },
      { id: 2, name: "Child Item 1.1", parentId: 1 },
      { id: 3, name: "Child Item 1.2", parentId: 1, dynamic: true },
      { id: 4, name: "Child Item 1.3", parentId: 1 },
    ]}'
    onLoadChildren="(node) => {
      loadCount++;
      delay(1000); 
      return ([
        { id: 5, name: `Dynamic Item 1.2.1 (${loadCount})` },
        { id: 6, name: `Dynamic Item 2.2.2 (${loadCount})` },
      ])
    }"
    >
    <property name="itemTemplate">
      <HStack testId="{$item.id}" verticalAlignment="center" gap="$space-1">
        <Icon name="{$item.hasChildren 
          ? ($item.loadingState === 'loaded' ? 'folder' : 'folder-outline' ) 
          : 'code'}" 
        />
        <Text>{$item.name}</Text>
      </HStack>
    </property>
  </Tree>
  <Button onClick="tree.markNodeUnloaded(3)">Unload</Button>
</App>

Properties

animateExpand (default: false)

When true, uses only the collapsed icon and rotates it for expansion instead of switching icons (default: false).

autoExpandToSelection (default: true)

Automatically expand the path to the selected item.

childrenField (default: "children")

The property name in source data for child arrays (used in hierarchy format).

data (required)

The data source of the tree. Format depends on the dataFormat property.

dataFormat (default: "flat")

The input data structure format: "flat" (array with parent relationships) or "hierarchy" (nested objects).

defaultExpanded (default: "none")

Initial expansion state: "none", "all", "first-level", or array of specific IDs.

dynamicField (default: "dynamic")

The property name in source data for dynamic loading state (default: "dynamic").

expandRotation (default: 90)

The number of degrees to rotate the collapsed icon when expanded in animate mode (default: 90).

iconCollapsed (default: "chevronright")

The icon name to use for collapsed nodes (default: "chevronright").

iconCollapsedField (default: "iconCollapsed")

The property name in source data for collapsed state icons.

iconExpanded (default: "chevrondown")

The icon name to use for expanded nodes (default: "chevrondown").

iconExpandedField (default: "iconExpanded")

The property name in source data for expanded state icons.

iconField (default: "icon")

The property name in source data for icon identifiers.

iconSize (default: "16")

The size of the expand/collapse icons (default: "16").

idField (default: "id")

The property name in source data for unique identifiers.

itemClickExpands (default: false)

Whether clicking anywhere on a tree item should expand/collapse the node, not just the expand/collapse icon.

itemHeight (default: 32)

The height of each tree row in pixels (default: 35).

itemTemplate

The template for each item in the tree.

nameField (default: "name")

The property name in source data for display text.

parentIdField (default: "parentId")

The property name in source data for parent relationships (used in flat format).

selectableField (default: "selectable")

The property name in source data for selectable state (default: "selectable").

selectedValue

The selected item ID in source data format.

Events

loadChildren

Fired when a tree node needs to load children dynamically. Should return an array of child data.

nodeDidCollapse

Fired when a tree node is collapsed.

nodeDidExpand

Fired when a tree node is expanded.

selectionDidChange

Fired when the tree selection changes.

Exposed Methods

appendNode

Add a new node to the tree as a child of the specified parent node.
Signature: appendNode(parentNodeId: string | number | null, nodeData: any): void
  • parentNodeId: The ID of the parent node, or null/undefined to add to root level
  • nodeData: The node data object using the format specified in dataFormat and field properties

clearSelection

Clear the current selection.
Signature: clearSelection(): void

collapseAll

Collapse all nodes in the tree.
Signature: collapseAll(): void

collapseNode

Collapse a specific node by its source data ID.
Signature: collapseNode(nodeId: string | number): void
  • nodeId: The ID of the node to collapse (source data format)

expandAll

Expand all nodes in the tree.
Signature: expandAll(): void

expandNode

Expand a specific node by its source data ID.
Signature: expandNode(nodeId: string | number): void
  • nodeId: The ID of the node to expand (source data format)

expandToLevel

Expand nodes up to the specified depth level (0-based).
Signature: expandToLevel(level: number): void
  • level: The maximum depth level to expand (0 = root level only)

getExpandedNodes

Get an array of currently expanded node IDs in source data format.
Signature: getExpandedNodes(): (string | number)[]

getNodeById

Get a tree node by its source data ID.
Signature: getNodeById(nodeId: string | number): TreeNode | null
  • nodeId: The ID of the node to retrieve (source data format)

getNodeLoadingState

Get the loading state of a dynamic node.
Signature: getNodeLoadingState(nodeId: string | number): NodeLoadingState
  • nodeId: The ID of the node to check loading state for

getSelectedNode

Get the currently selected tree node.
Signature: getSelectedNode(): TreeNode | null

insertNodeAfter

Insert a new node after an existing node at the same level.
Signature: insertNodeAfter(afterNodeId: string | number, nodeData: any): void
  • afterNodeId: The ID of the existing node after which the new node should be inserted
  • nodeData: The node data object using the format specified in dataFormat and field properties

insertNodeBefore

Insert a new node before an existing node at the same level.
Signature: insertNodeBefore(beforeNodeId: string | number, nodeData: any): void
  • beforeNodeId: The ID of the existing node before which the new node should be inserted
  • nodeData: The node data object using the format specified in dataFormat and field properties

markNodeLoaded

Mark a dynamic node as loaded.
Signature: markNodeLoaded(nodeId: string | number): void
  • nodeId: The ID of the node to mark as loaded

markNodeUnloaded

Mark a dynamic node as unloaded and collapse it.
Signature: markNodeUnloaded(nodeId: string | number): void
  • nodeId: The ID of the node to mark as unloaded

removeChildren

Remove all children (descendants) of a node while keeping the node itself.
Signature: removeChildren(nodeId: string | number): void
  • nodeId: The ID of the parent node whose children should be removed

removeNode

Remove a node and all its descendants from the tree.
Signature: removeNode(nodeId: string | number): void
  • nodeId: The ID of the node to remove (along with all its descendants)

scrollIntoView

Scroll to a specific node and expand parent nodes as needed to make it visible.
Signature: scrollIntoView(nodeId: string | number, options?: ScrollIntoViewOptions): void
  • nodeId: The ID of the node to scroll to (source data format)
  • options: Optional scroll options

scrollToItem

Scroll to a specific node if it's currently visible in the tree.
Signature: scrollToItem(nodeId: string | number): void
  • nodeId: The ID of the node to scroll to (source data format)

selectNode

Programmatically select a node by its source data ID.
Signature: selectNode(nodeId: string | number): void
  • nodeId: The ID of the node to select (source data format)

Styling

Theme Variables

VariableDefault Value (Light)Default Value (Dark)
backgroundColor-Tree-row--hover$color-surface-100$color-surface-100
backgroundColor-Tree-row--selected$color-primary-50$color-primary-50
borderColor-Tree-row--focus$color-primary-500$color-primary-500
outlineColor-Tree--focus$outlineColor--focus$outlineColor--focus
outlineOffset-Tree--focus$outlineOffset--focus$outlineOffset--focus
outlineStyle-Tree--focus$outlineStyle--focus$outlineStyle--focus
outlineWidth-Tree--focus$outlineWidth--focus$outlineWidth--focus
textColor-Tree$textColor-primary$textColor-primary
textColor-Tree--hover$textColor-primary$textColor-primary
textColor-Tree--selected$color-primary-900$color-primary-900