Navigation · astro-ui · TreeNew
TreeJS
Keyboard-navigable file/folder hierarchy with guide lines.
Tree renders a nested role="tree" from a plain items array — no markup authoring, no recursion in your page. Branches toggle aria-expanded, leaves with an href are real links, and one tab stop plus arrow keys give the whole hierarchy a single keyboard entry point. Because the structure is semantic, screen readers announce level and position for free.
Features
- Data-driven recursion via `Astro.self` — any depth, correct `aria-level`
- WAI-ARIA tree view keyboard model: arrows, Home/End, typeahead
- Single tab stop with roving focus; pointer clicks move it too
- Real links for leaves (`href`), so middle-click and copy-link work
- Disabled nodes are skipped by keyboard navigation
- Guide lines, twisties, and optional per-node icons
Usage
---
import { Tree } from "astro-ui";
---
<Tree
ariaLabel="Project files"
items={[
{
id: "src",
label: "src",
icon: "▸",
expanded: true,
children: [
{ id: "app", label: "App.astro" },
{ id: "lib", label: "lib", children: [{ id: "cn", label: "cn.ts" }] },
],
},
{ id: "pkg", label: "package.json" },
]}
/>Demos
Project files
- src
- App.astro
- lib
- cn.ts
- package.json
<Tree
ariaLabel="Project files"
items={[
{
id: "src",
label: "src",
icon: "▸",
expanded: true,
children: [
{ id: "app", label: "App.astro" },
{ id: "lib", label: "lib", children: [{ id: "cn", label: "cn.ts" }] },
],
},
{ id: "pkg", label: "package.json" },
]}
/>Deep hierarchy with links
<Tree
ariaLabel="Documentation"
selected="button"
items={[
{
id: "components",
label: "Components",
expanded: true,
children: [
{
id: "general",
label: "General",
expanded: true,
children: [
{ id: "button", label: "Button", href: "/components/button" },
{ id: "kbd", label: "Kbd", href: "/components/kbd" },
],
},
{
id: "overlay",
label: "Overlay",
expanded: true,
children: [
{ id: "menu", label: "Menu", href: "/components/menu" },
{ id: "sheet", label: "Sheet", href: "/components/sheet" },
],
},
],
},
]}
/>Disabled nodes
- main
- feat/tree
- release/1.0 (locked)
<Tree
ariaLabel="Branches"
items={[
{ id: "main", label: "main", expanded: true, children: [{ id: "a", label: "feat/tree" }] },
{ id: "locked", label: "release/1.0 (locked)", disabled: true },
]}
/>API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | TreeNode[] | — | The hierarchy; see the TreeNode shape below. |
ariaLabel | string | — | Accessible name for the tree (required). |
selected | string | — | Node id exposed as `aria-selected="true"`. |
class | string | — | Merged via cn(); Tailwind classes welcome. |
id | string | — | Element id. |
ariaLabel | string | — | Accessible name. |
Accessibility
Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.
role="tree"labelled byariaLabel(required)role="treeitem"witharia-levelandaria-expandedon branches- Nested children render in
role="group", hidden when collapsed - Derived keyboard model: → expand/enter, ← collapse/exit, ↑ ↓ move, Home/End, typeahead
- Disabled nodes expose
aria-disabledand never take focus selectedmarks the current item witharia-selected="true"
FAQ
What does a TreeNode look like?
`{ id: string; label: string; icon?: string; href?: string; children?: TreeNode[]; expanded?: boolean; disabled?: boolean }`. The presence of the `children` key marks a branch — an empty array renders a branch that expands to nothing.
How do I select nodes?
Tree is a navigation/disclosure widget: it toggles branches and follows links. For selection, listen for clicks on `[data-tree-node]` and render your own selected styling with `aria-selected`.
Why is the tree focusable as a whole?
It uses roving tabindex: exactly one item has `tabindex="0"` and arrow keys move that tab stop. Tabbing in lands on the last-focused node, then Tab leaves the tree — one stop, no keyboard trap.
Changelog
Version history mentioning Tree.
- Navigation (7): Tabs, Breadcrumb, Pagination, Stepper, Tree, Navbar, Sidebar.
- Native-first interactive behavior: Dialog, AlertDialog, and Sheet on
<dialog>; Accordion and Collapsible on<details>; Tabs, Menu, Tree, and Combobox with WAI-ARIA roles and scoped keyboard scripts.