Tree
<quiet-tree>
A hierarchical tree view for displaying nested content with expand/collapse and selection support.
Trees display hierarchical data with expandable/collapsible nodes and support for selection. They follow the ARIA APG tree view pattern for accessibility.
<quiet-tree label="Project files"> <quiet-tree-item expanded> <quiet-icon slot="icon" name="folder"></quiet-icon> src <quiet-tree-item> <quiet-icon slot="icon" name="folder"></quiet-icon> components <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> button.ts </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> input.ts </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> dialog.ts </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> tooltip.ts </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="folder"></quiet-icon> utilities <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> helpers.ts </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> format.ts </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> validate.ts </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="folder"></quiet-icon> styles <quiet-tree-item> <quiet-icon slot="icon" name="file-type-css"></quiet-icon> theme.css </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-css"></quiet-icon> reset.css </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> index.ts </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-code"></quiet-icon> package.json </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-code"></quiet-icon> tsconfig.json </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="markdown"></quiet-icon> README.md </quiet-tree-item> </quiet-tree>
For accessibility, you should add a label attribute to every tree. The label won't be
displayed, but it will be announced by assistive devices.
Hold Option or Alt to expand or collapse an entire branch at once.
Examples Jump to heading
Basic structure Jump to heading
Tree items can be nested inside other tree items to create a hierarchy. The item's label is the text or HTML content.
<quiet-tree label="Animal and plant categories"> <quiet-tree-item> Animals <quiet-tree-item> Cats <quiet-tree-item>Persian</quiet-tree-item> <quiet-tree-item>Siamese</quiet-tree-item> <quiet-tree-item>Maine Coon</quiet-tree-item> </quiet-tree-item> <quiet-tree-item> Dogs <quiet-tree-item>Golden Retriever</quiet-tree-item> <quiet-tree-item>Labrador</quiet-tree-item> </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> Plants <quiet-tree-item>Ferns</quiet-tree-item> <quiet-tree-item>Succulents</quiet-tree-item> </quiet-tree-item> </quiet-tree>
With icons Jump to heading
Use the icon slot to add icons to tree items. This works great with
<quiet-icon>.
<quiet-tree label="File browser"> <quiet-tree-item expanded> <quiet-icon slot="icon" name="folder"></quiet-icon> Documents <quiet-tree-item> <quiet-icon slot="icon" name="file-text"></quiet-icon> Notes.txt </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-pdf"></quiet-icon> Report.pdf </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="file-type-docx"></quiet-icon> Resume.docx </quiet-tree-item> </quiet-tree-item> <quiet-tree-item expanded> <quiet-icon slot="icon" name="folder"></quiet-icon> Images <quiet-tree-item> <quiet-icon slot="icon" name="photo"></quiet-icon> Meowy McGee.jpg </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="photo"></quiet-icon> Mittens.png </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="icon" name="photo"></quiet-icon> Whiskers.jpg </quiet-tree-item> </quiet-tree-item> </quiet-tree>
Expanded initially Jump to heading
Add the expanded attribute to any tree item that should be expanded when the page loads.
<quiet-tree label="Cat status"> <quiet-tree-item expanded> Awake cats <quiet-tree-item expanded> Currently playing <quiet-tree-item>Whiskers</quiet-tree-item> <quiet-tree-item>Luna</quiet-tree-item> </quiet-tree-item> <quiet-tree-item expanded> Taking a nap <quiet-tree-item>Mittens</quiet-tree-item> <quiet-tree-item>Shadow</quiet-tree-item> <quiet-tree-item>Oliver</quiet-tree-item> </quiet-tree-item> </quiet-tree-item> </quiet-tree>
Selection modes Jump to heading
Set the selection attribute to control how items can be selected. The default is
single.
single- Only one item can be selected at a timemultiple- Multiple items can be selected with checkboxes
<div id="tree__selection-modes"> <quiet-radio label="Selection mode" value="single"> <quiet-radio-item value="single">Single</quiet-radio-item> <quiet-radio-item value="multiple">Multiple</quiet-radio-item> </quiet-radio> <quiet-tree selection="single" label="Pet shop inventory"> <quiet-tree-item expanded> Cat Supplies <quiet-tree-item>Scratching Post</quiet-tree-item> <quiet-tree-item>Feather Wand</quiet-tree-item> <quiet-tree-item>Catnip Mouse</quiet-tree-item> </quiet-tree-item> <quiet-tree-item expanded> Cat Food <quiet-tree-item>Salmon Pate</quiet-tree-item> <quiet-tree-item>Chicken Chunks</quiet-tree-item> <quiet-tree-item>Turkey Giblets</quiet-tree-item> </quiet-tree-item> </quiet-tree> </div> <script> const container = document.getElementById('tree__selection-modes'); const tree = container.querySelector('quiet-tree'); const radio = container.querySelector('quiet-radio'); radio.addEventListener('input', () => { tree.selection = radio.value; }); </script> <style> #tree__selection-modes { quiet-radio { margin-block-end: 1.5rem; } } </style>
Multiple selection with cascade Jump to heading
In multiple selection mode, clicking a parent item will select or deselect all of its
descendants. The parent's checkbox will show an indeterminate state when some (but not all) children are
selected.
<quiet-tree selection="multiple" label="Pet selection"> <quiet-tree-item expanded> Select all cats <quiet-tree-item>Persian</quiet-tree-item> <quiet-tree-item>Siamese</quiet-tree-item> <quiet-tree-item>Maine Coon</quiet-tree-item> </quiet-tree-item> <quiet-tree-item expanded> Select all dogs <quiet-tree-item>Golden Retriever</quiet-tree-item> <quiet-tree-item>Labrador</quiet-tree-item> <quiet-tree-item>Poodle</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Allowing deselection Jump to heading
Add the allow-deselect attribute to clear the selection when clicking outside the tree or
pressing Esc. This works in both single and multiple selection modes.
<quiet-tree allow-deselect label="Cat treats"> <quiet-tree-item expanded> Select a treat, then click outside <quiet-tree-item>Tuna Flakes</quiet-tree-item> <quiet-tree-item>Chicken Bites</quiet-tree-item> <quiet-tree-item>Salmon Treats</quiet-tree-item> <quiet-tree-item>Freeze-dried Shrimp</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Initially selected Jump to heading
Add the selected attribute to tree items that should be selected when the page loads.
<quiet-tree selection="single" label="Cat preferences"> <quiet-tree-item expanded> Cat Preferences <quiet-tree-item>Feeding Schedule</quiet-tree-item> <quiet-tree-item selected>Favorite Nap Spots</quiet-tree-item> <quiet-tree-item>Toy Rotation</quiet-tree-item> <quiet-tree-item>Grooming Needs</quiet-tree-item> <quiet-tree-item>Vet Appointments</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Disabled items Jump to heading
Add the disabled attribute to prevent interaction with specific tree items.
<quiet-tree label="Adoption status"> <quiet-tree-item expanded> Adoption Status <quiet-tree-item>Available Now</quiet-tree-item> <quiet-tree-item disabled>Pending (disabled)</quiet-tree-item> <quiet-tree-item>Foster Only</quiet-tree-item> <quiet-tree-item>Medical Hold</quiet-tree-item> <quiet-tree-item>Reserved</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Disabled tree Jump to heading
Add the disabled attribute to the tree itself to disable all interaction.
<quiet-tree disabled label="Sleeping cats"> <quiet-tree-item expanded> Sleeping Cats (do not disturb) <quiet-tree-item>Whiskers</quiet-tree-item> <quiet-tree-item>Mittens</quiet-tree-item> <quiet-tree-item>Shadow</quiet-tree-item> <quiet-tree-item>Luna</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Custom expand icon Jump to heading
Use the expand-icon slot to provide a custom expand/collapse icon. The icon will rotate 90
degrees when expanded.
<quiet-tree id="tree__custom-icon" label="Cat toys"> <quiet-tree-item expanded> <quiet-icon slot="expand-icon" name="plus"></quiet-icon> Cat Toys <quiet-tree-item> <quiet-icon slot="expand-icon" name="plus"></quiet-icon> Feather Wand </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="expand-icon" name="plus"></quiet-icon> Laser Pointer </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="expand-icon" name="plus"></quiet-icon> Catnip Mouse </quiet-tree-item> <quiet-tree-item> <quiet-icon slot="expand-icon" name="plus"></quiet-icon> Crinkle Ball </quiet-tree-item> </quiet-tree-item> </quiet-tree> <style> #tree__custom-icon { quiet-tree-item::part(expand-icon) { transition: 150ms rotate ease; } quiet-tree-item:state(expanded)::part(expand-icon) { rotate: 45deg; } } </style>
Handling selection changes Jump to heading
Listen for the quiet-select event to respond to selection changes. The event detail contains
the selected item(s).
Selected: None
<div id="tree__events"> <quiet-tree selection="single" label="Cat breeds"> <quiet-tree-item expanded> Pick a cat breed <quiet-tree-item>Persian</quiet-tree-item> <quiet-tree-item>Siamese</quiet-tree-item> <quiet-tree-item>Maine Coon</quiet-tree-item> <quiet-tree-item>Bengal</quiet-tree-item> <quiet-tree-item>Ragdoll</quiet-tree-item> <quiet-tree-item>British Shorthair</quiet-tree-item> </quiet-tree-item> </quiet-tree> <br> Selected: <span id="tree__events-output">None</span> </div> <script> const container = document.getElementById('tree__events'); const tree = container.querySelector('quiet-tree'); const output = document.getElementById('tree__events-output'); tree.addEventListener('quiet-select', event => { const item = event.detail.item; output.textContent = item.textContent?.trim().split('\n')[0] || 'Unknown'; }); </script>
Preventing expand/collapse Jump to heading
Listen for quiet-before-expand or quiet-before-collapse events and call
event.preventDefault() to prevent the action. This is useful for lazy loading or confirmation
dialogs.
<quiet-tree id="tree__prevent" label="Cat locations"> <quiet-tree-item id="tree__prevent-expand"> Secret Cat Hideout <quiet-tree-item>You won't find me here</quiet-tree-item> <quiet-tree-item>Or here</quiet-tree-item> <quiet-tree-item>Definitely not here</quiet-tree-item> </quiet-tree-item> <quiet-tree-item id="tree__prevent-collapse" expanded> Always Watching <quiet-tree-item>The bird feeder</quiet-tree-item> <quiet-tree-item>The squirrel</quiet-tree-item> <quiet-tree-item>The mailman</quiet-tree-item> </quiet-tree-item> </quiet-tree> <script> const tree = document.getElementById('tree__prevent'); const preventExpand = document.getElementById('tree__prevent-expand'); const preventCollapse = document.getElementById('tree__prevent-collapse'); tree.addEventListener('quiet-before-expand', event => { if (event.detail.item === preventExpand) { event.preventDefault(); } }); tree.addEventListener('quiet-before-collapse', event => { if (event.detail.item === preventCollapse) { event.preventDefault(); } }); </script> <style> #tree__prevent { quiet-tree-item::part(expand-icon) { cursor: not-allowed; } } </style>
Lazy loading Jump to heading
Use the lazy attribute to show an expand icon even when there are no children. Use the
loading attribute to show a spinner. When the user tries to expand, prevent the default
behavior, show the spinner, load your data, then call expand() to complete the expansion.
<div id="tree__lazy"> <quiet-tree label="Remote files"> <quiet-tree-item id="tree__lazy-item" lazy> <quiet-icon slot="icon" name="folder"></quiet-icon> Remote folder (click to load) </quiet-tree-item> </quiet-tree> <br> <quiet-button>Reset</quiet-button> </div> <script> const container = document.getElementById('tree__lazy'); const tree = container.querySelector('quiet-tree'); const lazyItem = tree.querySelector('quiet-tree-item[lazy]'); const resetButton = container.querySelector('quiet-button'); tree.addEventListener('quiet-before-expand', async event => { const item = event.detail.item; // Only handle lazy items if (!item.lazy) return; // Prevent default so we can load data first event.preventDefault(); // Show the loading spinner item.loading = true; try { // Simulate fetching children from a server await new Promise(resolve => setTimeout(resolve, 1000)); // Add children to the tree const files = ['document.pdf', 'image.png', 'data.json']; files.forEach(file => { const child = document.createElement('quiet-tree-item'); child.innerHTML = `<quiet-icon slot="icon" name="file"></quiet-icon>${file}`; item.appendChild(child); }); // Remove lazy, hide spinner, and expand to show new children item.lazy = false; item.loading = false; item.expand(); } catch { // Hide spinner on error item.loading = false; } }); resetButton.addEventListener('click', () => { // Remove all children and reset to lazy state lazyItem.querySelectorAll('quiet-tree-item').forEach(child => child.remove()); lazyItem.lazy = true; lazyItem.expanded = false; }); </script>
Programmatic control Jump to heading
Use the expandAll(), collapseAll(), and getSelectedItems() methods to
control the tree programmatically.
<div id="tree__programmatic"> <div class="button-group"> <quiet-button id="expand-all">Expand All</quiet-button> <quiet-button id="collapse-all">Collapse All</quiet-button> <quiet-button id="get-selected">Log Selected</quiet-button> </div> <quiet-tree selection="multiple" label="Cat roster"> <quiet-tree-item> Indoor Cats <quiet-tree-item> Kittens <quiet-tree-item>Whiskers</quiet-tree-item> <quiet-tree-item>Mittens</quiet-tree-item> <quiet-tree-item>Patches</quiet-tree-item> </quiet-tree-item> <quiet-tree-item> Adults <quiet-tree-item>Luna</quiet-tree-item> <quiet-tree-item>Oliver</quiet-tree-item> </quiet-tree-item> </quiet-tree-item> <quiet-tree-item> Outdoor Cats <quiet-tree-item>Shadow</quiet-tree-item> <quiet-tree-item>Tiger</quiet-tree-item> <quiet-tree-item>Smokey</quiet-tree-item> </quiet-tree-item> </quiet-tree> </div> <script> const container = document.getElementById('tree__programmatic'); const tree = container.querySelector('quiet-tree'); const expandAllButton = document.getElementById('expand-all'); const collapseAllButton = document.getElementById('collapse-all') const getSelectedButton = document.getElementById('get-selected') expandAllButton.addEventListener('click', () => { tree.expandAll(); }); collapseAllButton.addEventListener('click', () => { tree.collapseAll(); }); getSelectedButton.addEventListener('click', () => { console.log(tree.getSelectedItems()); }); </script> <style> #tree__programmatic { .button-group { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-block-end: 1rem; } } </style>
Customizing indent guides Jump to heading
Use the --guide-color, --guide-width, and --indent-size custom
properties to customize the appearance of indent guides.
<quiet-tree id="tree__custom-guides" label="Cat family tree"> <quiet-tree-item expanded> Cat Family Tree <quiet-tree-item expanded> Mama Cat <quiet-tree-item expanded> First Litter <quiet-tree-item>Fluffy Jr.</quiet-tree-item> <quiet-tree-item>Patches</quiet-tree-item> <quiet-tree-item>Snowball</quiet-tree-item> </quiet-tree-item> <quiet-tree-item> Second Litter <quiet-tree-item>Whiskers</quiet-tree-item> <quiet-tree-item>Mittens</quiet-tree-item> </quiet-tree-item> </quiet-tree-item> </quiet-tree-item> </quiet-tree> <style> #tree__custom-guides { --indent-size: 2rem; --guide-color: var(--quiet-primary-stroke-soft); --guide-width: 2px; } </style>
Hiding indent guides Jump to heading
Add the without-guides attribute to hide the indent guide lines.
<quiet-tree without-guides label="Cat hiding spots"> <quiet-tree-item expanded> Cat Hiding Spots <quiet-tree-item expanded> Upstairs <quiet-tree-item>Under the bed</quiet-tree-item> <quiet-tree-item>Behind the curtains</quiet-tree-item> <quiet-tree-item>Inside the closet</quiet-tree-item> </quiet-tree-item> <quiet-tree-item expanded> Downstairs <quiet-tree-item>Inside the box</quiet-tree-item> <quiet-tree-item>Behind the couch</quiet-tree-item> <quiet-tree-item>Under the blanket</quiet-tree-item> </quiet-tree-item> </quiet-tree-item> </quiet-tree>
Changing the animation Jump to heading
Use the --duration and --easing properties to customize expand/collapse
animations.
<quiet-tree label="Cat stretching sequence" style="--duration: 800ms; --easing: cubic-bezier(0.68, -0.6, 0.32, 1.6);"> <quiet-tree-item> Cat stretching in slow motion <quiet-tree-item>Front paws extend</quiet-tree-item> <quiet-tree-item>Back arches gracefully</quiet-tree-item> <quiet-tree-item>Tail curls upward</quiet-tree-item> <quiet-tree-item>Big satisfying yawn</quiet-tree-item> <quiet-tree-item>Returns to napping</quiet-tree-item> </quiet-tree-item> </quiet-tree>
Styling trees Jump to heading
Style icons based on file type to create a VS Code-like appearance. Add classes to tree items and use CSS to color the icons.
<quiet-tree id="tree__colored-icons" label="Project files"> <quiet-tree-item class="folder" expanded> <quiet-icon slot="icon" name="folder"></quiet-icon> src <quiet-tree-item class="ts"> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> app.ts </quiet-tree-item> <quiet-tree-item class="ts"> <quiet-icon slot="icon" name="file-type-ts"></quiet-icon> types.ts </quiet-tree-item> <quiet-tree-item class="css"> <quiet-icon slot="icon" name="file-type-css"></quiet-icon> styles.css </quiet-tree-item> <quiet-tree-item class="html"> <quiet-icon slot="icon" name="file-type-html"></quiet-icon> index.html </quiet-tree-item> <quiet-tree-item class="json"> <quiet-icon slot="icon" name="file-code"></quiet-icon> config.json </quiet-tree-item> <quiet-tree-item class="md"> <quiet-icon slot="icon" name="markdown"></quiet-icon> README.md </quiet-tree-item> </quiet-tree-item> </quiet-tree> <style> #tree__colored-icons { /* Indent guide color */ --guide-color: color-mix(in oklab, #f43f5e 25%, transparent); /* Expand icon color */ quiet-tree-item::part(expand-icon) { color: #f43f5e; } /* Selected state - 25% transparent background */ quiet-tree-item:state(selected)::part(row) { background-color: rgb(99 102 241 / 25%); color: inherit; } /* Focus state - full opacity outline */ quiet-tree-item::part(row):focus-visible { outline: 2px solid #6366f1; } /* Icon colors by file type */ .folder > quiet-icon { color: #f59e0b; } .ts > quiet-icon { color: #0ea5e9; } .css > quiet-icon { color: #ec4899; } .html > quiet-icon { color: #10b981; } .json > quiet-icon { color: #f97316; } .md > quiet-icon { color: #06b6d4; } } </style>
API Jump to heading
Importing Jump to heading
The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.
To manually import <quiet-tree> from the CDN, use the following code.
import 'https://cdn.quietui.org/v2.4.0/components/tree/tree.js';
To manually import <quiet-tree> from a self-hosted distribution, use the following
code. Remember to replace /path/to/quiet with the appropriate local path.
import '/path/to/quiet/components/tree/tree.js';
Slots Jump to heading
Tree supports the following slots. Learn more about using slots
| Name | Description |
|---|---|
| (default) | One or more <quiet-tree-item> elements. |
Properties Jump to heading
Tree has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties
| Property / Attribute | Description | Reflects | Type | Default |
|---|---|---|---|---|
label
|
An accessible label for the tree. This won't be visible, but it will be announced by assistive devices. |
|
string
|
|
selection
|
The selection mode for the tree. |
|
'single'
|
'single'
|
disabled
|
Disables the entire tree. |
|
boolean
|
false
|
withoutGuides
without-guides
|
Hides the indent guide lines. |
|
boolean
|
false
|
allowDeselect
allow-deselect
|
When enabled, clicking outside of the tree will clear the selection. |
|
boolean
|
false
|
Methods Jump to heading
Tree supports the following methods. You can obtain a reference to the element and call them like functions in JavaScript. Learn more about methods
| Name | Description | Arguments |
|---|---|---|
getSelectedItems() |
Gets all currently selected tree items. | |
expandAll() |
Expands all tree items. | |
collapseAll() |
Collapses all tree items. | |
clearSelection() |
Clears all selected items and emits a quiet-select event.
|
|
focus() |
Sets focus to the first focusable item in the tree. |
options: FocusOptions
|
blur() |
Removes focus from the tree. |
Events Jump to heading
Tree dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events
| Name | Description |
|---|---|
quiet-before-expand |
Emitted before an item expands. Call event.preventDefault() to prevent expansion.
event.detail.item contains the tree item.
|
quiet-expand |
Emitted after an item has expanded and the animation completes.
event.detail.item contains the tree item.
|
quiet-before-collapse |
Emitted before an item collapses. Call event.preventDefault() to prevent collapse.
event.detail.item contains the tree item.
|
quiet-collapse |
Emitted after an item has collapsed and the animation completes.
event.detail.item contains the tree item.
|
quiet-select |
Emitted when the selection changes. event.detail.item contains the selected item(s), or
an empty array when the selection is cleared.
|
CSS custom properties Jump to heading
Tree supports the following CSS custom properties. You can style them like any other CSS property. Learn more about CSS custom properties
| Name | Description | Default |
|---|---|---|
--duration |
The duration of expand/collapse animations. |
150ms
|
--easing |
The easing function for expand/collapse animations. |
ease
|
--guide-color |
The color of indent guide lines. | |
--guide-width |
The width of indent guide lines. |
1px
|
--indent-size |
The indentation size per nesting level. |
1.5rem
|
Custom States Jump to heading
Tree has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states
| Name | Description | CSS selector |
|---|---|---|
disabled |
Applied when the tree is disabled. |
:state(disabled)
|
Dependencies Jump to heading
Tree automatically imports the following elements. Sub-dependencies are also included in this list.