Component to display tree-like data structure
<div
role="tree"
[tuiTreeController]="true"
>
<tui-tree-item>
Fruits
<tui-tree-item>
Apples
<tui-tree-item>Granny Smith</tui-tree-item>
<tui-tree-item>Red Delicious</tui-tree-item>
</tui-tree-item>
<tui-tree-item>Oranges</tui-tree-item>
</tui-tree-item>
<tui-tree-item>
Animals
<tui-tree-item>Cats</tui-tree-item>
<tui-tree-item>Dogs</tui-tree-item>
</tui-tree-item>
</div>
<tui-tree [value]="data" />
tui-tree {
margin-inline-start: -3.5rem;
}
<tui-tree
[childrenHandler]="handler"
[content]="content"
[tuiTreeController]="true"
[value]="data"
/>
<ng-template
#content
let-node="node"
let-value
>
<div
class="wrapper"
[style.opacity]="1 / node.level"
>
@if (value.icon) {
<tui-icon
class="t-icon"
[icon]="value.icon"
/>
}
{{ value.text }}
</div>
</ng-template>
.wrapper {
display: flex;
align-items: center;
}
.t-icon::before {
font-size: 1rem;
}
<tui-tree
[childrenHandler]="handler"
[content]="content"
[map]="map"
[tuiTreeController]="false"
[value]="data"
/>
<ng-template
#content
let-item
>
{{ item.text }}
</ng-template>
<p>
<button
size="s"
tuiButton
type="button"
class="programmatic tui-space_right-2"
(click)="toggleTopmost()"
>
Toggle Topmost
</button>
</p>
<p>
<button
size="s"
tuiButton
type="button"
class="programmatic"
(click)="toggleLevel(0)"
>
Toggle Top level 1
</button>
</p>
<button
size="s"
tuiButton
type="button"
class="programmatic"
(click)="toggleLevel(2)"
>
Toggle Top level 3
</button>
@for (item of data.children; track item) {
<tui-tree
[childrenHandler]="handler"
[content]="content"
[tuiTreeController]="true"
[value]="item"
/>
}
<ng-template
#content
let-item
>
{{ item.text }}
</ng-template>
tui-tree {
overflow: hidden;
}
@for (item of data.children; track item) {
<tui-tree
[childrenHandler]="handler"
[content]="content"
[tuiTreeController]="true"
[value]="item"
/>
}
<ng-template
#content
let-item
>
<label
tuiLabel
class="tui-space_vertical-2 tui-space_left-1"
>
<input
size="s"
tuiCheckbox
type="checkbox"
[ngModel]="item | tuiMapper: getValue : map"
(ngModelChange)="onChecked(item, $event)"
/>
<small>{{ item.text }}</small>
</label>
</ng-template>
<tui-tree
[childrenHandler]="childrenHandler"
[content]="content"
[map]="map"
[tuiTreeController]="false"
[value]="service.data$ | async"
(toggled)="onToggled($event)"
/>
<ng-template
#content
let-item
>
@if (item === loading) {
<tui-loader class="loader" />
} @else {
{{ item.text }}
}
</ng-template>
.loader {
inline-size: 2rem;
margin: 1rem 0;
}
<tui-tree
class="tree"
[childrenHandler]="handler"
[class._dragged]="drag()"
[content]="content"
[tuiTreeController]="true"
[value]="data"
>
<ng-template
#content
let-value
>
@if (!value.children) {
<div class="wrapper">
<div
class="drop"
(pointerup)="onDrop(value)"
></div>
<tui-tiles class="tiles">
<tui-tile>
<div
tuiTileHandle
class="content"
(pointerdown)="onDrag(value)"
>
{{ value.text }}
</div>
</tui-tile>
</tui-tiles>
<div
class="drop"
(pointerup)="onDrop(value, 1)"
></div>
</div>
} @else {
{{ value.text }}
}
</ng-template>
</tui-tree>
.tree._dragged {
.drop {
pointer-events: auto;
&:hover {
opacity: 1;
}
}
}
.wrapper {
position: relative;
inline-size: 100%;
}
.content {
display: flex;
inline-size: 100%;
align-items: center;
}
.tiles {
inline-size: 100%;
grid-template-rows: 1.5rem;
}
.drop {
position: absolute;
z-index: 1;
inline-size: 100%;
block-size: 0.5rem;
margin-block-start: -0.25rem;
background: #87ceeb;
border-radius: 1rem;
opacity: 0;
pointer-events: none;
}