Tree overview
Headless tree owns navigation, expansion, selection, and typeahead behavior for hierarchical views. You own the row markup, branch connectors, disclosure visuals, and collapsed-group presentation.
Primitive imports
ts
import {
TngTree,
TngTreeItem,
TngTreeGroup,
TngTreeIndicator,
} from '@tailng-ui/primitives';Basic composition
Compose a root controller, one focusable tree item per node, nested groups for children, and an optional indicator that toggles the branch. The primitive does not create rows or hide collapsed groups for you.
Headless tree composition
html
<div
tngTree
[selectionMode]="'single'"
[defaultValue]="'button'"
aria-label="Project files"
>
<div tngTreeItem [value]="'src'" [defaultExpanded]="true">
<span class="tree-node-row">
<span tngTreeIndicator class="tree-indicator">📂</span>
src
</span>
<div tngTreeGroup class="tree-node-group">
<div tngTreeItem [value]="'components'" [defaultExpanded]="true">
<span class="tree-node-row">
<span tngTreeIndicator class="tree-indicator">📂</span>
components
</span>
<div tngTreeGroup class="tree-node-group">
<div tngTreeItem [value]="'button'">
<span class="tree-node-row">
<span class="tree-icon">📄</span>
button.ts
</span>
</div>
</div>
</div>
</div>
</div>
</div>Style variants
The same primitive tree rendered through a plain CSS contract or a Tailwind utility shell.
Headless tree (plain CSS)
📂 src
📂 components
button.ts
input.ts
utils.ts
Headless tree (Tailwind CSS)
Accessibility baseline
- Root controller exposes
role="tree"and manages the active roving item. - Each tree item exposes
role="treeitem"witharia-expandedonly for branch nodes. - Selection state is mirrored through
aria-selectedanddata-selected. - Owners must hide collapsed child groups visually and provide meaningful visible or
aria-labeltext for typeahead.