A NavigationTree provides users with a way to navigate a nested, hierarchical set of links.
Content
NavigationTree follows the Collection Components API, accepting both static and dynamic collections. The example above shows a static collection. This example shows a dynamic collection, passing a list of objects to the items prop and a function to render the children.
import {NavigationTree, NavigationTreeItem, NavigationTreeItemContent, NavigationTreeItemLink} from './NavigationTree';
import {Router, Link as RouterLink} from './Router';
function Example() {
let items = [
{id: 'overview', url: '/overview', label: 'Overview'},
{id: 'reports', url: '/reports', label: 'Reports'},
{id: 'settings', url: '/settings', label: 'Settings'}
];
return (
<Router defaultSelectedRoute="/reports">
{({selectedRoute}) => (
<NavigationTree aria-label="Sections" items={items} selectedRoute={selectedRoute} renderLink={props => <RouterLink {...props} />}>
{item => (
<NavigationTreeItem href={item.url} textValue={item.label}>
<NavigationTreeItemContent>
<NavigationTreeItemLink>{item.label}</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
)}
</NavigationTree>
)}
</Router>
);
}
Accessibility
NavigationTree renders as a tree so keyboard users can navigate and expand the hierarchy. When it acts as the main navigation for a page, place it inside a navigation landmark: wrap the NavigationTree in a <nav> element with an aria-label so assistive technology users can quickly find it.Sections
Use NavigationTreeSection to group related items, with an optional NavigationTreeHeader to label each group. Sections without a header must have an aria-label.
import {NavigationTree, NavigationTreeItem, NavigationTreeItemContent, NavigationTreeItemLink, NavigationTreeSection, NavigationTreeHeader} from './NavigationTree';
import {Router, Link as RouterLink} from './Router';
<Router defaultSelectedRoute="/projects/apollo">
{({selectedRoute}) => (
<NavigationTree aria-label="Workspace" selectedRoute={selectedRoute} renderLink={props => <RouterLink {...props} />}>
<NavigationTreeSection>
<NavigationTreeHeader>Personal</NavigationTreeHeader>
<NavigationTreeItem href="/home" textValue="Home">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Home</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
<NavigationTreeItem href="/starred" textValue="Starred">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Starred</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
</NavigationTreeSection>
<NavigationTreeSection>
<NavigationTreeHeader>Projects</NavigationTreeHeader>
<NavigationTreeItem href="/projects/apollo" textValue="Apollo">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Apollo</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
<NavigationTreeItem href="/projects/gemini" textValue="Gemini">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Gemini</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
</NavigationTreeSection>
</NavigationTree>
)}
</Router>
Current route
Each NavigationTreeItem accepts an href. Set the selectedRoute prop on the NavigationTree to the current page's path, and the item whose href matches is marked with aria-current="page" (and a data-current attribute for styling).
import {NavigationTree, NavigationTreeItem, NavigationTreeItemContent, NavigationTreeItemLink} from './NavigationTree';
import {Router, Link as RouterLink} from './Router';
<Router defaultSelectedRoute="/inbox">
{({selectedRoute}) => (
<NavigationTree aria-label="Mail" selectedRoute={selectedRoute} renderLink={props => <RouterLink {...props} />}>
<NavigationTreeItem href="/inbox" textValue="Inbox">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Inbox</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
<NavigationTreeItem href="/drafts" textValue="Drafts">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Drafts</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
<NavigationTreeItem href="/sent" textValue="Sent">
<NavigationTreeItemContent>
<NavigationTreeItemLink>Sent</NavigationTreeItemLink>
</NavigationTreeItemContent>
</NavigationTreeItem>
</NavigationTree>
)}
</Router>
To integrate with a client side router, use the render prop on Link to delegate to your router's link component. This supports features like prefetching on hover and avoids full page reloads.
Get the current route from your framework and pass it as selectedRoute.
import {NavigationTree, NavigationTreeItem, NavigationTreeItemContent} from './NavigationTree';
import {Link} from 'react-aria-components/Link';
import NextLink from 'next/link';
import {usePathname} from 'next/navigation';
function Sidebar() {
let selectedRoute = usePathname();
return (
<NavigationTree selectedRoute={selectedRoute}>
<NavigationTreeItem href="/inbox" textValue="Inbox">
<NavigationTreeItemContent>
<Link render={props => <NextLink {...props} />}>Inbox</Link>
</NavigationTreeItemContent>
</NavigationTreeItem>
</NavigationTree>
);
}
API
<NavigationTree>
<NavigationTreeSection>
<NavigationTreeHeader />
<NavigationTreeItem>
<NavigationTreeItemContent>
<Link />
<Button slot="chevron" />
</NavigationTreeItemContent>
</NavigationTreeItem>
</NavigationTreeSection>
</NavigationTree>
NavigationTree
A NavigationTree provides users with a way to navigate a nested, hierarchical set of links.
| Name | Type | |
|---|---|---|
selectedRoute | string | null | |
The route that is currently selected, matched against each item's | ||
expandedKeys | Iterable | |
The currently expanded keys in the collection (controlled). | ||
defaultExpandedKeys | Iterable | |
The initial expanded keys in the collection (uncontrolled). | ||
children | ReactNode | | |
The contents of the collection. | ||
items | Iterable | |
Item objects in the collection. | ||
dependencies | ReadonlyArray | |
Values that should invalidate the item cache when using dynamic collections. | ||
disabledKeys | Iterable | |
The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | ||
Default className: react-aria-NavigationTree
| Render Prop | CSS Selector |
|---|---|
isEmpty | CSS Selector: [data-empty]
|
| Whether the tree has no items and should display its empty state. | |
isFocused | CSS Selector: [data-focused]
|
| Whether the tree is currently focused. | |
isFocusVisible | CSS Selector: [data-focus-visible]
|
| Whether the tree is currently keyboard focused. | |
state | CSS Selector: — |
| State of the tree. | |
NavigationTreeItem
A NavigationTreeItem represents an individual item in a NavigationTree.
| Name | Type | |
|---|---|---|
children | ReactNode | |
The content of the side nav item along with any nested children. Supports static nested side nav items or use of a Collection to dynamically render nested side nav items. | ||
id | Key | |
The unique id of the tree row. | ||
textValue | string | |
A string representation of the tree item's contents, used for features like typeahead. | ||
isDisabled | boolean | |
Whether the item is disabled. | ||
hasChildItems | boolean | |
Whether this item has children, even if not loaded yet. | ||
Default className: react-aria-NavigationTreeItem
| Render Prop | CSS Selector |
|---|---|
isCurrent | CSS Selector: [data-current]
|
Whether this item is the current route (its href matches the NavigationTree's
selectedRoute). | |
isCurrentAncestor | CSS Selector: [data-current-ancestor]
|
| Whether this item is an ancestor of the current-route item (at any level, regardless of whether it is expanded or collapsed). | |
isExpanded | CSS Selector: [data-expanded]
|
| Whether the tree item is expanded. | |
hasChildItems | CSS Selector: [data-has-child-items]
|
| Whether the tree item has child tree items. | |
level | CSS Selector: [data-level="number"]
|
| What level the tree item has within the tree. | |
isFocusVisibleWithin | CSS Selector: [data-focus-visible-within]
|
| Whether the tree item's children have keyboard focus. | |
state | CSS Selector: — |
| The state of the tree. | |
id | CSS Selector: — |
| The unique id of the tree row. | |
isHovered | CSS Selector: [data-hovered]
|
| Whether the item is currently hovered with a mouse. | |
isPressed | CSS Selector: [data-pressed]
|
| Whether the item is currently in a pressed state. | |
isSelected | CSS Selector: [data-selected]
|
| Whether the item is currently selected. | |
isFocused | CSS Selector: [data-focused]
|
| Whether the item is currently focused. | |
isFocusVisible | CSS Selector: [data-focus-visible]
|
| Whether the item is currently keyboard focused. | |
isDisabled | CSS 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. | |
selectionMode | CSS Selector: [data-selection-mode="single | multiple"]
|
| The type of selection that is allowed in the collection. | |
selectionBehavior | CSS Selector: — |
| The selection behavior for the collection. | |
NavigationTreeItemContent
| Name | Type | |
|---|---|---|
children | ChildrenOrFunction | |
The children of the component. A function may be provided to alter the children based on component state. | ||
NavigationTreeSection
A NavigationTreeSection represents a section within a NavigationTree.
| Name | Type | |
|---|---|---|
id | Key | |
The unique id of the section. | ||
children | ReactNode | | |
Static child items or a function to render children. | ||
items | Iterable | |
Item objects in the section. | ||
dependencies | ReadonlyArray | |
Values that should invalidate the item cache when using dynamic collections. | ||
NavigationTreeHeader
A NavigationTreeHeader renders the header of a NavigationTreeSection.
| Name | Type | |
|---|---|---|
children | ReactNode | |
The children of the component. | ||