<!-- Generated by tools/docs.php from docs/src/tree.html - edit the source, not this file. -->

# Trees

Pages under pages, a menu's items, folders: a list whose items open their own lists, each a link or a name, and moved by a handle.

## Examples

`tree` on the list, `tree-item` on each item, its `tree-row` holding a `tree-toggle` - a `--toggle` button naming the item's `tree-group` in `aria-controls`, as on [collapse](collapse.md) - and the item's link. The groups close as `hidden="until-found"`, so the browser's find in page still opens them. A button with `command="--expand-all"` or `"--collapse-all"` for the tree opens or closes every group that holds items.

```html
<div class="hstack gap-8">
	<button class="btn btn-sm" type="button" commandfor="tree-pages-list" command="--expand-all"><i class="bi bi-arrows-expand" aria-hidden="true"></i>Expand all</button>
	<button class="btn btn-sm" type="button" commandfor="tree-pages-list" command="--collapse-all"><i class="bi bi-arrows-collapse" aria-hidden="true"></i>Collapse all</button>
</div>
<ul class="tree" id="tree-pages-list" aria-label="Pages">
	<li class="tree-item">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text tree-toggle" type="button" command="--toggle" aria-controls="tree-pages-excursions" aria-expanded="true" aria-label="Excursions"><i class="bi bi-chevron-right" aria-hidden="true"></i></button>
			<a href="#tree-pages">Excursions</a>
		</div>
		<ul class="tree-group" id="tree-pages-excursions">
			<li class="tree-item"><div class="tree-row"><a href="#tree-pages">North Bay by speedboat</a></div></li>
			<li class="tree-item"><div class="tree-row"><a href="#tree-pages">Night market and street food</a></div></li>
		</ul>
	</li>
	<li class="tree-item">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text tree-toggle" type="button" command="--toggle" aria-controls="tree-pages-islands" aria-expanded="false" aria-label="Islands"><i class="bi bi-chevron-right" aria-hidden="true"></i></button>
			<a href="#tree-pages">Islands</a>
		</div>
		<ul class="tree-group" id="tree-pages-islands" hidden="until-found">
			<li class="tree-item"><div class="tree-row"><a href="#tree-pages">Turtle Cove</a></div></li>
			<li class="tree-item"><div class="tree-row"><a href="#tree-pages">Moon Cove</a></div></li>
		</ul>
	</li>
	<li class="tree-item">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text tree-toggle" type="button" command="--toggle" aria-controls="tree-pages-archive" aria-expanded="false" aria-label="Archive"><i class="bi bi-chevron-right" aria-hidden="true"></i></button>
			<a href="#tree-pages">Archive</a>
		</div>
		<ul class="tree-group" id="tree-pages-archive" hidden="until-found" data-lazy data-docs-lazy></ul>
	</li>
	<li class="tree-item"><div class="tree-row"><a href="#tree-pages">Contacts</a></div></li>
</ul>
```

### Children from the server

A group with `data-lazy` and no items fires `redz:expand` on it when it first opens. A page that loads the items cancels it and answers with a promise: the toggle is busy until it settles, and a refusal closes the group again for another try. The Archive above answers after 400 ms.

```js
document.addEventListener('redz:expand', (event) => {
	event.preventDefault();
	event.detail.respondWith(fetch('/pages?parent=' + event.target.dataset.parent)
		.then((answer) => answer.text())
		.then((items) => event.target.insertAdjacentHTML('beforeend', items)));
});
```

### Moved by a handle

A tree with `data-reorder` moves its items as a list does - see [reordering](list-group.md#list-group-reorder) - and its menu of moves adds `data-move="in"`, to the end of the group of the item above, and `"out"`, after its parent; an item can go in where the item above has a `tree-group`, empty or not. `data-parent` names the hidden field of each item's parent, its value the item's key.

```html
<ul class="tree" id="tree-menu-list" aria-label="The site's menu" data-reorder="menu[]" data-parent="menu_parent">
	<li class="tree-item" data-value="home">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text drag-handle" type="button" commandfor="tree-menu-moves" command="toggle-popover" aria-haspopup="menu" aria-label="Move: Home"><i class="bi bi-grip-vertical" aria-hidden="true"></i></button>
			<span>Home</span>
		</div>
		<ul class="tree-group" id="tree-menu-home"></ul>
	</li>
	<li class="tree-item" data-value="tours">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text drag-handle" type="button" commandfor="tree-menu-moves" command="toggle-popover" aria-haspopup="menu" aria-label="Move: Tours"><i class="bi bi-grip-vertical" aria-hidden="true"></i></button>
			<span>Tours</span>
		</div>
		<ul class="tree-group" id="tree-menu-tours">
			<li class="tree-item" data-value="boats">
				<div class="tree-row">
					<button class="btn btn-sm btn-icon btn-text drag-handle" type="button" commandfor="tree-menu-moves" command="toggle-popover" aria-haspopup="menu" aria-label="Move: Boats"><i class="bi bi-grip-vertical" aria-hidden="true"></i></button>
					<span>Boats</span>
				</div>
				<ul class="tree-group" id="tree-menu-boats"></ul>
			</li>
		</ul>
	</li>
	<li class="tree-item" data-value="contacts">
		<div class="tree-row">
			<button class="btn btn-sm btn-icon btn-text drag-handle" type="button" commandfor="tree-menu-moves" command="toggle-popover" aria-haspopup="menu" aria-label="Move: Contacts"><i class="bi bi-grip-vertical" aria-hidden="true"></i></button>
			<span>Contacts</span>
		</div>
		<ul class="tree-group" id="tree-menu-contacts"></ul>
	</li>
</ul>
<div class="menu" id="tree-menu-moves" popover role="menu" aria-label="Move">
	<button class="menu-item" type="button" role="menuitem" data-move="up"><i class="bi bi-arrow-up" aria-hidden="true"></i>Move up</button>
	<button class="menu-item" type="button" role="menuitem" data-move="down"><i class="bi bi-arrow-down" aria-hidden="true"></i>Move down</button>
	<button class="menu-item" type="button" role="menuitem" data-move="in"><i class="bi bi-arrow-return-right flip-rtl" aria-hidden="true"></i>Move into the item above</button>
	<button class="menu-item" type="button" role="menuitem" data-move="out"><i class="bi bi-arrow-bar-left flip-rtl" aria-hidden="true"></i>Move out</button>
</div>
```

### The current page, actions and checks

A row whose link has `aria-current` - the page open now - is tinted and its link bold. `tree-actions` at the end of a row holds its buttons: quiet until the row is hovered, holds the focus or has a menu open on a pointer screen, always shown on a touch screen. A `check` in a row posts by its own name, for a batch over the chosen pages. A search with [`data-filter`](list-group.md#list-group-filter) keeps the parents of a match.

```html
<input class="form-control" type="search" data-filter="tree-current-list" aria-label="Find a page" placeholder="Find a page" autocomplete="off">
<ul class="tree" id="tree-current-list" aria-label="Pages to publish">
	<li class="tree-item">
		<div class="tree-row">
			<input class="check" type="checkbox" name="pages[]" value="excursions" aria-label="Choose: Excursions">
			<a href="#tree-current">Excursions</a>
			<span class="tree-actions"><button class="btn btn-xs btn-icon btn-text" type="button" aria-label="Add a page under Excursions"><i class="bi bi-plus-lg" aria-hidden="true"></i></button></span>
		</div>
		<ul class="tree-group">
			<li class="tree-item">
				<div class="tree-row">
					<input class="check" type="checkbox" name="pages[]" value="north-bay" aria-label="Choose: North Bay by speedboat" checked>
					<a href="#tree-current" aria-current="page">North Bay by speedboat</a>
					<span class="tree-actions"><button class="btn btn-xs btn-icon btn-text" type="button" aria-label="Add a page under North Bay by speedboat"><i class="bi bi-plus-lg" aria-hidden="true"></i></button></span>
				</div>
			</li>
			<li class="tree-item">
				<div class="tree-row">
					<input class="check" type="checkbox" name="pages[]" value="night-market" aria-label="Choose: Night market and street food">
					<a href="#tree-current">Night market and street food</a>
					<span class="tree-actions"><button class="btn btn-xs btn-icon btn-text" type="button" aria-label="Add a page under Night market and street food"><i class="bi bi-plus-lg" aria-hidden="true"></i></button></span>
				</div>
			</li>
		</ul>
	</li>
</ul>
```

## Keyboard and accessibility

- The tree is a list of lists with buttons and links - the disclosure pattern: Tab goes from one control to the next, `Enter` or `Space` opens or closes a group, and the toggle says it in `aria-expanded`. It is not the ARIA tree widget, which the APG itself keeps for choosing, not for links.
- A toggle is named after its item; its chevron points along the line of reading, mirrored right to left.
- The moves are a menu on the handle, so a keyboard, a screen reader and a single tap move an item as a drag does; after a move the focus stays on the moved item's handle and its new place is said politely.

## Tokens

From [`css/components/tree.css`](https://github.com/redz-tech/REDZ.UI/blob/main/css/components/tree.css), which declares no custom property of its own.

It reads the theme's `--redz-space-12`, `--redz-space-8`, `--redz-border`, `--redz-space-4`, `--redz-control-height`, `--redz-control-height-sm`, `--redz-radius-6`, `--redz-primary-subtle`, `--redz-text`, `--redz-motion`, `--redz-ease`.
