Overview for tree

The mat-tree provides a Material Design styled tree that can be used to display hierarchical data.

This tree builds on the foundation of the CDK tree and uses a similar interface for its data source input and template, except that its element and attribute selectors will be prefixed with mat- instead of cdk-.

There are two types of trees: flat and nested. The DOM structures are different for these two types of trees.

In a flat tree, the hierarchy is flattened; nodes are not rendered inside of each other, but instead are rendered as siblings in sequence.

<mat-tree>
  <mat-tree-node> parent node </mat-tree-node>
  <mat-tree-node> -- child node1 </mat-tree-node>
  <mat-tree-node> -- child node2 </mat-tree-node>
</mat-tree>
Tree with flat nodes (childrenAccessor)
Fruit Vegetables

Flat trees are generally easier to style and inspect. They are also more friendly to scrolling variations, such as infinite or virtual scrolling.

In a nested tree, children nodes are placed inside their parent node in DOM. The parent node contains a node outlet into which children are projected.

<mat-tree>
   <mat-nested-tree-node>
     parent node
     <mat-nested-tree-node> -- child node1 </mat-nested-tree-node>
     <mat-nested-tree-node> -- child node2 </mat-nested-tree-node>
   </mat-nested-tree-node>
</mat-tree>
Tree with nested nodes (childrenAccessor)
Fruit
Apple Banana Fruit loops
Vegetables
Green
Broccoli Brussels sprouts
Orange
Pumpkins Carrots

Nested trees are easier to work with when hierarchical relationships are visually represented in ways that would be difficult to accomplish with flat nodes.

In order to use the tree, you must define a tree node template. There are two types of tree nodes, <mat-tree-node> for flat tree and <mat-nested-tree-node> for nested tree. The tree node template defines the look of the tree node, expansion/collapsing control and the structure for nested children nodes.

A node definition is specified via any element with matNodeDef. This directive exports the node data to be used in any bindings in the node template.

<mat-tree-node *matNodeDef="let node">
  {{node.key}}: {{node.value}}
</mat-tree-node>

Flat trees use the level of a node to both render and determine hierarchy of the nodes for screen readers. This may be provided either via levelAccessor, or will be calculated by MatTree if childrenAccessor is provided.

Spacing can be added either by applying the matNodePadding directive or by applying custom styles based on the aria-level attribute.

When using nested tree nodes, the node template must contain a matTreeNodeOutlet, which marks where the children of the node will be rendered.

<mat-nested-tree-node *matNodeDef="let node">
  {{node.value}}
  <ng-container matTreeNodeOutlet></ng-container>
</mat-nested-tree-node>

The matTreeNodeToggle directive can be used to add expand/collapse functionality for tree nodes. The toggle calls the expand/collapse functions in the matTree and is able to expand/collapse a tree node recursively by setting [matTreeNodeToggleRecursive] to true.

matTreeNodeToggle should be attached to button elements, and will trigger upon click or keyboard activation. For icon buttons, ensure that aria-label is provided.

<mat-tree-node *matNodeDef="let node">
  <button matTreeNodeToggle aria-label="toggle tree node" [matTreeNodeToggleRecursive]="true">
    <mat-icon>expand</mat-icon>
  </button>
  {{node.value}}
</mat-tree-node>

A matTreeNodeToggle can be added in the tree node template to expand/collapse the tree node. The toggle toggles the expand/collapse functions in TreeControl and is able to expand/collapse a tree node recursively by setting [matTreeNodeToggleRecursive] to true.

The toggle can be placed anywhere in the tree node, and is only toggled by click action.

The matTreeNodePadding can be placed in a flat tree's node template to display the level information of a flat tree node.

<mat-tree-node *matNodeDef="let node" matNodePadding>
  {{node.value}}
</mat-tree-node>

This is unnecessary for a nested tree, since the hierarchical structure of the DOM allows for padding to be added via CSS.

The tree may include multiple node templates, where a template is chosen for a particular data node via the when predicate of the template.

<mat-tree-node *matNodeDef="let node" matTreeNodePadding>
  {{node.value}}
</mat-tree-node>
<mat-tree-node *matNodeDef="let node; when: isSpecial" matTreeNodePadding>
  [ A special node {{node.value}} ]
</mat-tree-node>

Similar to mat-table, you can provide data to the tree through a DataSource. When the tree receives a DataSource it will call its connect() method which returns an observable that emits an array of data. Whenever the data source emits data to this stream, the tree will render an update.

Because the data source provides this stream, it bears the responsibility of toggling tree updates. This can be based on anything: tree node expansion change, websocket connections, user interaction, model updates, time-based intervals, etc.

There are two main methods of providing data to the tree:

  • flattened data, combined with levelAccessor. This should be used if the data source already flattens the nested data structure into a single array.
  • only root data, combined with childrenAccessor. This should be used if the data source is already provided as a nested data structure.

levelAccessor is a function that when provided a datum, returns the level the data sits at in the tree structure. If levelAccessor is provided, the data provided by dataSource should contain all renderable nodes in a single array.

The data source is responsible for handling node expand/collapse events and providing an updated array of renderable nodes, if applicable. This can be listened to via the (expansionChange) event on mat-tree-node and mat-nested-tree-node.

childrenAccessor is a function that when provided a datum, returns the children of that particular datum. If childrenAccessor is provided, the data provided by dataSource should only contain the root nodes of the tree.

To improve performance, a trackBy function can be provided to the tree similar to Angular’s ngFor trackBy. This informs the tree how to uniquely identify nodes to track how the data changes with each update.

<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" [trackBy]="trackByFn">

The <mat-tree> implements the tree widget, including keyboard navigation and appropriate roles and ARIA attributes.

In order to use the new accessibility features, migrating to levelAccessor and childrenAccessor is required. Trees using treeControl do not implement the correct accessibility features for backwards compatibility.

In order for the tree to correctly determine whether or not a node is expandable, the isExpandable property must be set on all mat-tree-node or mat-tree-nested-node that are expandable.

For trees with nodes that have actions upon activation or click, <mat-tree-node> will emit (activation) events that can be listened to when the user activates a node via keyboard interaction.

<mat-tree-node
    *matNodeDef="let node"
    (click)="performAction(node)"
    (activation)="performAction($event)">
</mat-tree-node>

In this example, $event contains the node's data and is equivalent to the implicit data passed in the matNodeDef context.

Azure & Blue theme selected.