Skip to content

TreeView

A hierarchical list of items where nested items can be expanded and collapsed.
  • Beta
  • Reviewed for accessibility
import {TreeView} from '@primer/react'

Examples

With React Router

import {Link, useMatch, useResolvedPath, navigate} from 'react-router-dom'
import {TreeView} from '@primer/react/drafts'
function TreeLinkItem({id, to, children}) {
const resolved = useResolvedPath(to)
const isCurrent = useMatch({path: resolved.pathname, end: true})
return (
<TreeList.Item
id={id}
aria-current={isCurrent ? 'page' : undefined}
current={isCurrent}
onSelect={() => navigate(to)}
>
{children}
</TreeList.Item>
)
}
function App() {
return (
<nav aria-label="Files">
<TreeView aria-label="Files">
<TreeLinkItem id="src/Avatar.tsx" to="/src/Avatar.tsx">
Avatar.tsx
</TreeLinkItem>
<TreeLinkItem id="src/Button.tsx" to="/src/Button.tsx">
Button.tsx
</TreeLinkItem>
</TreeView>
</nav>
)
}

With Next.js

import {useRouter} from 'next/router'
import Link from 'next/link'
import {TreeView} from '@primer/react/drafts'
function TreeLinkItem({id, href, children}) {
const router = useRouter()
const isCurrent = typeof href === 'string' ? router.asPath === href : router.pathname === href.pathname
return (
<Link href={href} passHref>
<TreeView.Item id={id} aria-current={isCurrent ? 'page' : false} current={isCurrent}>
{children}
</TreeView.Item>
</Link>
)
}
function App() {
return (
<nav aria-label="Files">
<TreeView aria-label="Files">
<TreeLinkItem id="src/Avatar.tsx" href="/src/Avatar.tsx">
Avatar.tsx
</TreeLinkItem>
<TreeLinkItem
id="src/Button.tsx"
// You can also pass a URL object
// https://nextjs.org/docs/api-reference/next/link#with-url-object
href={{
pathname: '/src/[component].[filetype]',
query: {component: 'Button', filetype: 'tsx'},
}}
>
Button.tsx
</TreeLinkItem>
</TreeView>
</nav>
)
}

With controlled expanded state

With stateful visuals

To render stateful visuals, pass a render function to TreeView.LeadingVisual or TreeView.TrailingVisual. The function will be called with the expanded state of the item.

Since stateful directory icons are a common use case for TreeView, we provide a TreeView.DirectoryIcon component for convenience. The previous example can be rewritten as:

With asynchronously loaded items

See Storybook for examples with asynchronously loaded items.

Props

TreeView

NameTypeDefaultDescription
children Required
React.ReactNode

TreeView.Item

NameTypeDefaultDescription
children Required
React.ReactNode
id Required
string
A unique identifier for the item.
current
boolean
falseIndicates whether the item is the current item. No more than one item should be current at once. The path to the current item will be expanded by default.
defaultExpanded
boolean
The expanded state of the item when it is initially rendered. Use when you do not need to control the state.
expanded
boolean
The controlled expanded state of item. Must be used in conjunction with onExpandedChange.
containIntrinsicSize
string
The size of this item's contents. Passing this will set 'content-visiblity: auto' on the content container, delaying rendering until the item is in the viewport.
onExpandedChange
(expanded: boolean) => void
Event handler called when the expanded state of the item changes.
onSelect
(event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => void
ref
React.Ref<HTMLElement>
A ref to the element rendered by this component.

TreeView.LeadingVisual

NameTypeDefaultDescription
children Required
| React.ReactNode
| (props: {isExpanded: boolean}) => React.ReactNode)
label
string
Provide an accessible label for the visual. This is not necessary for decorative visuals.

TreeView.TrailingVisual

NameTypeDefaultDescription
children Required
| React.ReactNode
| (props: {isExpanded: boolean}) => React.ReactNode)
label
string
Provide an accessible label for the visual. This is not necessary for decorative visuals.

TreeView.DirectoryIcon

No props

TreeView.SubTree

NameTypeDefaultDescription
children
React.ReactNode
state
| 'initial'
| 'loading'
| 'done'
| 'error'
Specify a state if items in the subtree are loaded asynchronously. An asynchronous subtree can be in one of the following states: 'initial', 'loading', 'done', or 'error'. In the 'initial' state, items are neither loaded nor loading. In the 'loading' state, items are loading and the subtree will render a loading indicator. In the 'done' state, items are loaded. Screen readers will announce when a subtree enters the 'done' state. An 'error' state means that an error occured while loading items.
count
number
The number of items expected to be in the subtree. When in the loading state, the subtree will render a skeleton loading placeholder with the specified count of items

TreeView.ErrorDialog

NameTypeDefaultDescription
children Required
React.ReactNode
The content of the dialog. This is usually a message explaining the error.
title
string
'Error'The title of the dialog. This is usually a short description of the error.
onRetry
() => void
Event handler called when the user clicks the retry button.
onDismiss
() => void
Event handler called when the dialog is dismissed.

Status

Alpha

  • Component props and basic example usage of the component are documented on primer.style/react.
  • Component does not have any unnecessary third-party dependencies.
  • Component can adapt to different themes.
  • Component can adapt to different screen sizes.
  • Component has robust unit test coverage (100% where achievable).
  • Component has visual regression coverage of its default and interactive states.
  • Component does not introduce any axe violations.
  • Component has been manually reviewed by the accessibility team and any resulting issues have been addressed.

Beta

  • Component is used in a production application.
  • Common usage examples are documented on primer.style/react.
  • Common usage examples are documented in storybook stories.
  • Component has been reviewed by a systems designer and any resulting issues have been addressed.
  • Component does not introduce any performance regressions.

Stable

  • Component API has been stable with no breaking changes for at least one month.
  • Feedback on API usability has been sought from developers using the component and any resulting issues have been addressed.
  • Component has corresponding design guidelines documented in the interface guidelines.
  • Component has corresponding Figma component in the Primer Web library.
  • Tooling (such as linters, codemods, etc.) exists to prevent further use of alternatives.