Tree

A tree provides users with a way to navigate nested hierarchical information, with support for keyboard navigation and selection.

Theme 
selectionMode 
Example
Tree.tsx
Tree.css
import {Tree, TreeItem} from './Tree';

<Tree
  selectionMode="multiple"
  aria-label="Files">
  <TreeItem title="Documents">
    <TreeItem title="Project">
      <TreeItem title="Weekly Report" />
    </TreeItem>
  </TreeItem>
  <TreeItem title="Photos">
    <TreeItem title="Image 1" />
    <TreeItem title="Image 2" />
  </TreeItem>
</Tree>

Content

Tree follows the Collection Components API, accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the items prop, and a recursive function to render the children.

Documents
import {Tree, TreeItem} from './Tree';
import {Collection} from 'react-aria-components';

<Tree aria-label="Files" defaultExpandedKeys={[1, 4]} items={items} selectionMode="multiple"> {function renderItem(item) {
return ( <TreeItem title={item.title}> {/* recursively render children */} <Collection items={item.children}> {renderItem} </Collection> </TreeItem> ); }} </Tree>

Asynchronous loading

Use renderEmptyState to display a spinner during initial load. To enable infinite scrolling, render a <TreeLoadMoreItem> at the end of each <TreeItem>. Use whatever data fetching library you prefer – this example uses useAsyncList from react-stately.

import {Tree, TreeItem, TreeLoadMoreItem} from './Tree';
import {ProgressCircle} from './ProgressCircle';
import {Collection, useAsyncList} from 'react-aria-components';

interface Character {
  name: string
}

function AsyncLoadingExample() {
return ( <Tree aria-label="Async loading tree" style={{height: 300}} renderEmptyState={() => ( <ProgressCircle isIndeterminate aria-label="Loading..." /> )}> <TreeItem title="Pokemon"> <Collection items={pokemonList.items}>
{(item) => <TreeItem id={item.name} title={item.name} />} </Collection> <TreeLoadMoreItem onLoadMore={pokemonList.loadMore} isLoading={pokemonList.loadingState === 'loadingMore'} /> </TreeItem> <TreeItem title="Star Wars"> <Collection items={starWarsList.items}> {(item) => <TreeItem id={item.name} title={item.name} />} </Collection> <TreeLoadMoreItem onLoadMore={starWarsList.loadMore} isLoading={starWarsList.loadingState === 'loadingMore'} /> </TreeItem> </Tree> ); }

Use the href prop on a <TreeItem> to create a link. See the framework setup guide to learn how to integrate with your framework. Link interactions vary depending on the selection behavior. See the selection guide for more details.

Bulbasaur
Ivysaur
Venusaur
selectionBehavior 
import {Tree, TreeItem} from './Tree';

<Tree
  selectionMode="multiple"
  aria-label="Tree with links"
  defaultExpandedKeys={['bulbasaur', 'ivysaur']}>
  <TreeItem
    href="https://pokemondb.net/pokedex/bulbasaur"
    target="_blank"
    id="bulbasaur"
    title="Bulbasaur">
    <TreeItem
      id="ivysaur"
      title="Ivysaur"
      href="https://pokemondb.net/pokedex/ivysaur"
      target="_blank">
      <TreeItem
        id="venusaur"
        title="Venusaur"
        href="https://pokemondb.net/pokedex/venusaur"
        target="_blank" />
    </TreeItem>
  </TreeItem>
</Tree>

Empty state

No results found.
import {Tree} from './Tree';

<Tree
  aria-label="Search results"
  renderEmptyState={() => 'No results found.'}>
  {[]}
</Tree>

Selection and actions

Use the selectionMode prop to enable single or multiple selection. The selected items can be controlled via the selectedKeys prop, matching the id prop of the items. The onAction event handles item actions. Items can be disabled with the isDisabled prop. See the selection guide for more details.

Bulbasaur
Ivysaur
Venusaur

Current selection:

selectionMode 
selectionBehavior 
disabledBehavior 
disallowEmptySelection 
import type {Selection} from 'react-aria-components';
import {Tree, TreeItem} from './Tree';
import {useState} from 'react';

function Example(props) {
  let [selected, setSelected] = useState<Selection>(new Set());

  return (
    <div>
      <Tree
        {...props}
        aria-label="Pokemon evolution"
        style={{height: 250}}
        defaultExpandedKeys={['bulbasaur', 'ivysaur']}
        selectionMode="multiple"
        selectedKeys={selected}
        onSelectionChange={setSelected}
        onAction={key => alert(`Clicked ${key}`)}
      >
        <TreeItem id="bulbasaur" title="Bulbasaur">
          <TreeItem id="ivysaur" title="Ivysaur">
            <TreeItem id="venusaur" title="Venusaur" isDisabled />
          </TreeItem>
        </TreeItem>
        <TreeItem id="charmander" title="Charmander">
          <TreeItem id="charmeleon" title="Charmeleon">
            <TreeItem id="charizard" title="Charizard" />
          </TreeItem>
        </TreeItem>
        <TreeItem id="squirtle" title="Squirtle">
          <TreeItem id="wartortle" title="Wartortle">
            <TreeItem id="blastoise" title="Blastoise" />
          </TreeItem>
        </TreeItem>
      </Tree>
      <p>Current selection: {selected === 'all' ? 'all' : [...selected].join(', ')}</p>
    </div>
  );
}

Drag and drop

Tree supports drag and drop interactions when the dragAndDropHooks prop is provided using the hook. Users can drop data on the list as a whole, on individual items, insert new items between existing ones, or reorder items. React Aria supports drag and drop via mouse, touch, keyboard, and screen reader interactions. See the drag and drop guide to learn more.

import {Tree, TreeItem} from './Tree';
import {useDragAndDrop, Collection, useTreeData} from 'react-aria-components';

function Example() {
let {dragAndDropHooks} = useDragAndDrop({ getItems: (keys, items: typeof tree.items) => items.map(item => ({'text/plain': item.value.title})), onMove(e) { if (e.target.dropPosition === 'before') { tree.moveBefore(e.target.key, e.keys); } else if (e.target.dropPosition === 'after') { tree.moveAfter(e.target.key, e.keys); } else if (e.target.dropPosition === 'on') { // Move items to become children of the target let targetNode = tree.getItem(e.target.key); if (targetNode) { let targetIndex = targetNode.children ? targetNode.children.length : 0; let keyArray = Array.from(e.keys); for (let i = 0; i < keyArray.length; i++) { tree.move(keyArray[i], e.target.key, targetIndex + i); } } } } }); return ( <Tree aria-label="Tree with hierarchical drag and drop" selectionMode="multiple" items={tree.items} dragAndDropHooks={dragAndDropHooks} > {function renderItem(item) { return ( <TreeItem title={item.value.title}> {item.children && <Collection items={item.children}> {renderItem} </Collection>} </TreeItem> ) }} </Tree> ); }

Examples

API

DocumentsTreeItemCheckbox (optional)12 itemsOnboardingPDFBudgetXLSSales PitchPPTCollapse and expand buttonTree
<Tree>
  <TreeItem>
    <TreeItemContent>
      <Button slot="chevron" />
      <Checkbox slot="selection" /> or <SelectionIndicator />
      <Button slot="drag" />
    </TreeItemContent>
    <TreeItem>
      {/* ... */}
    </TreeItem>
    <TreeLoadMoreItem />
  </TreeItem>
</Tree>

Tree

A tree provides users with a way to navigate nested hierarchical information, with support for keyboard navigation and selection.

NameType
dragAndDropHooks<NoInfer<object>>
The drag and drop hooks returned by useDragAndDrop used to enable drag and drop behavior for the Tree.
expandedKeysIterable<Key>
The currently expanded keys in the collection (controlled).
defaultExpandedKeysIterable<Key>
The initial expanded keys in the collection (uncontrolled).
childrenReactNode(item: object) => ReactNode
The contents of the collection.
itemsIterable<T>
Item objects in the collection.
renderEmptyState(props: ) => ReactNode
Provides content to display when there are no items in the list.
dependenciesReadonlyArray<any>
Values that should invalidate the item cache when using dynamic collections.
selectionMode
The type of selection that is allowed in the collection.
selectionBehavior
How multiple selection should behave in the tree.
selectedKeys'all'Iterable<Key>
The currently selected keys in the collection (controlled).
defaultSelectedKeys'all'Iterable<Key>
The initial selected keys in the collection (uncontrolled).
onSelectionChange(keys: ) => void
Handler that is called when the selection changes.
disabledKeysIterable<Key>
The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.
disabledBehavior
Whether disabledKeys applies to all interactions, or only selection.
disallowEmptySelectionboolean
Whether the collection allows empty selection.
shouldSelectOnPressUpboolean
Whether selection should occur on press up instead of press down.
escapeKeyBehavior'clearSelection''none'
Whether pressing the escape key should clear selection in the grid list or not. Most experiences should not modify this option as it eliminates a keyboard user's ability to easily clear selection. Only use if the escape key is being handled externally or should not trigger selection clearing contextually.

Default className: react-aria-Tree

Render PropCSS Selector
isEmptyCSS Selector: [data-empty]
Whether the tree has no items and should display its empty state.
isFocusedCSS Selector: [data-focused]
Whether the tree is currently focused.
isFocusVisibleCSS Selector: [data-focus-visible]
Whether the tree is currently keyboard focused.
selectionModeCSS Selector: [data-selection-mode="single | multiple"]
The type of selection that is allowed in the collection.
allowsDraggingCSS Selector: [data-allows-dragging]
Whether the tree allows dragging.
stateCSS Selector:
State of the tree.

TreeItem

A TreeItem represents an individual item in a Tree.

NameType
idKey
The unique id of the tree row.
valueobject
The object value that this tree item represents. When using dynamic collections, this is set automatically.
textValuestring
A string representation of the tree item's contents, used for features like typeahead.
childrenReactNode
The content of the tree item along with any nested children. Supports static nested tree items or use of a Collection to dynamically render nested tree items.
isDisabledboolean
Whether the item is disabled.
hasChildItemsboolean
Whether this item has children, even if not loaded yet.

Default className: react-aria-TreeItem

Render PropCSS Selector
isExpandedCSS Selector: [data-expanded]
Whether the tree item is expanded.
hasChildItemsCSS Selector: [data-has-child-items]
Whether the tree item has child tree items.
levelCSS Selector: [data-level="number"]
What level the tree item has within the tree.
isFocusVisibleWithinCSS Selector: [data-focus-visible-within]
Whether the tree item's children have keyboard focus.
stateCSS Selector:
The state of the tree.
idCSS Selector:
The unique id of the tree row.
isHoveredCSS Selector: [data-hovered]
Whether the item is currently hovered with a mouse.
isPressedCSS Selector: [data-pressed]
Whether the item is currently in a pressed state.
isSelectedCSS Selector: [data-selected]
Whether the item is currently selected.
isFocusedCSS Selector: [data-focused]
Whether the item is currently focused.
isFocusVisibleCSS Selector: [data-focus-visible]
Whether the item is currently keyboard focused.
isDisabledCSS Selector: [data-disabled]
Whether the item is non-interactive, i.e. both selection and actions are disabled and the item may not be focused. Dependent on disabledKeys and disabledBehavior.
selectionModeCSS Selector: [data-selection-mode="single | multiple"]
The type of selection that is allowed in the collection.
selectionBehaviorCSS Selector:
The selection behavior for the collection.
CSS Variable
--tree-item-level
The depth of the item within the tree. Useful to calculate indentation.

TreeItemContent

NameType
children<>
The children of the component. A function may be provided to alter the children based on component state.

TreeLoadMoreItem

NameTypeDefault
children<>Default:
The load more spinner to render when loading additional items.
isLoadingbooleanDefault:
Whether or not the loading spinner should be rendered or not.
scrollOffsetnumberDefault: 1
The amount of offset from the bottom of your scrollable region that should trigger load more. Uses a percentage value relative to the scroll body's client height. Load more is then triggered when your current scroll position's distance from the bottom of the currently loaded list of items is less than or equal to the provided value. (e.g. 1 = 100% of the scroll region's height).
onLoadMore() => anyDefault:
Handler that is called when more items should be loaded, e.g. while scrolling near the bottom.

Default className: react-aria-TreeLoadMoreItem

Render PropCSS Selector
levelCSS Selector: [data-level]
What level the tree item has within the tree.
CSS Variable
--tree-item-level
The depth of the item within the tree. Useful to calculate indentation.