TreeView
A tree view provides users with a way to navigate nested hierarchical information.
install | yarn add @react-spectrum/tree |
---|---|
version | 3.0.0-beta.1 |
usage | import {TreeView, TreeViewItem} from '@react-spectrum/tree' |
Example#
<TreeView
aria-label="Example tree with static contents"
defaultExpandedKeys={new Set(['documents', 'photos'])}
height="size-4600"
maxWidth="size-6000"
>
<TreeViewItem id="documents" textValue="Documents">
<Text>Documents</Text>
<Folder />
<TreeViewItem id="project-a" textValue="Project A">
<Text>Project A</Text>
<Folder />
<TreeViewItem id="weekly-report" textValue="Weekly-Report">
<Text>Weekly Report</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem id="document-1" textValue="Document 1">
<Text>Document 1</Text>
<FileTxt />
</TreeViewItem>
<TreeViewItem id="document-2" textValue="Document 2">
<Text>Document 2</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem id="photos" textValue="Photos">
<Text>Photos</Text>
<Folder />
<TreeViewItem id="image-1" textValue="Image 1">
<Text>Image 1</Text>
<Image />
</TreeViewItem>
<TreeViewItem id="image-2" textValue="Image 2">
<Text>Image 2</Text>
<Image />
</TreeViewItem>
<TreeViewItem id="image-3" textValue="Image 3">
<Text>Image 3</Text>
<Image />
</TreeViewItem>
</TreeViewItem>
</TreeView>
<TreeView
aria-label="Example tree with static contents"
defaultExpandedKeys={new Set(['documents', 'photos'])}
height="size-4600"
maxWidth="size-6000"
>
<TreeViewItem id="documents" textValue="Documents">
<Text>Documents</Text>
<Folder />
<TreeViewItem id="project-a" textValue="Project A">
<Text>Project A</Text>
<Folder />
<TreeViewItem
id="weekly-report"
textValue="Weekly-Report"
>
<Text>Weekly Report</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem id="document-1" textValue="Document 1">
<Text>Document 1</Text>
<FileTxt />
</TreeViewItem>
<TreeViewItem id="document-2" textValue="Document 2">
<Text>Document 2</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem id="photos" textValue="Photos">
<Text>Photos</Text>
<Folder />
<TreeViewItem id="image-1" textValue="Image 1">
<Text>Image 1</Text>
<Image />
</TreeViewItem>
<TreeViewItem id="image-2" textValue="Image 2">
<Text>Image 2</Text>
<Image />
</TreeViewItem>
<TreeViewItem id="image-3" textValue="Image 3">
<Text>Image 3</Text>
<Image />
</TreeViewItem>
</TreeViewItem>
</TreeView>
<TreeView
aria-label="Example tree with static contents"
defaultExpandedKeys={new Set(
[
'documents',
'photos'
]
)}
height="size-4600"
maxWidth="size-6000"
>
<TreeViewItem
id="documents"
textValue="Documents"
>
<Text>
Documents
</Text>
<Folder />
<TreeViewItem
id="project-a"
textValue="Project A"
>
<Text>
Project A
</Text>
<Folder />
<TreeViewItem
id="weekly-report"
textValue="Weekly-Report"
>
<Text>
Weekly Report
</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem
id="document-1"
textValue="Document 1"
>
<Text>
Document 1
</Text>
<FileTxt />
</TreeViewItem>
<TreeViewItem
id="document-2"
textValue="Document 2"
>
<Text>
Document 2
</Text>
<FileTxt />
</TreeViewItem>
</TreeViewItem>
<TreeViewItem
id="photos"
textValue="Photos"
>
<Text>Photos</Text>
<Folder />
<TreeViewItem
id="image-1"
textValue="Image 1"
>
<Text>
Image 1
</Text>
<Image />
</TreeViewItem>
<TreeViewItem
id="image-2"
textValue="Image 2"
>
<Text>
Image 2
</Text>
<Image />
</TreeViewItem>
<TreeViewItem
id="image-3"
textValue="Image 3"
>
<Text>
Image 3
</Text>
<Image />
</TreeViewItem>
</TreeViewItem>
</TreeView>
Content#
TreeView is a collection component that provides users with a way to navigate nested hierarchical information.
Basic usage of TreeView, seen in the example above, shows the use of a static collection where the contents of the TreeView are hard coded. Dynamic collections, as shown below, can be used when the options come from an external data source, such as an API, or update over time. Providing the data in this way allows TreeView to automatically cache the rendering of each item, which dramatically improves performance.
Items can be statically defined as children, or generated dynamically using a function based on the data passed to the items
prop.
Each item has a unique key defined by the data. The key
of each item element is implicitly defined by the id property of the item object. See collections to learn more about keys in dynamic collections.
type MyItem = {
id: string;
name: string;
icon: JSX.Element;
childItems?: MyItem[];
};
let items: MyItem[] = [
{
id: 'projects',
name: 'Projects',
icon: <Folder />,
childItems: [
{ id: 'project-1', name: 'Project 1', icon: <FileTxt /> },
{
id: 'project-2',
name: 'Project 2',
icon: <Folder />,
childItems: [
{ id: 'document-a', name: 'Document A', icon: <FileTxt /> },
{ id: 'document-b', name: 'Document B', icon: <FileTxt /> }
]
}
]
},
{
id: 'reports',
name: 'Reports',
icon: <Folder />,
childItems: [
{ id: 'report-1', name: 'Reports 1', icon: <FileTxt /> }
]
}
];
function ExampleTree(props) {
return (
<TreeView
aria-label="Example tree with dynamic content"
height="size-3000"
maxWidth="size-6000"
items={items}
{...props}
>
{(item: MyItem) => (
<TreeViewItem childItems={item.childItems} textValue={item.name}>
<Text>{item.name}</Text>
{item.icon}
</TreeViewItem>
)}
</TreeView>
);
}
type MyItem = {
id: string;
name: string;
icon: JSX.Element;
childItems?: MyItem[];
};
let items: MyItem[] = [
{
id: 'projects',
name: 'Projects',
icon: <Folder />,
childItems: [
{
id: 'project-1',
name: 'Project 1',
icon: <FileTxt />
},
{
id: 'project-2',
name: 'Project 2',
icon: <Folder />,
childItems: [
{
id: 'document-a',
name: 'Document A',
icon: <FileTxt />
},
{
id: 'document-b',
name: 'Document B',
icon: <FileTxt />
}
]
}
]
},
{
id: 'reports',
name: 'Reports',
icon: <Folder />,
childItems: [
{
id: 'report-1',
name: 'Reports 1',
icon: <FileTxt />
}
]
}
];
function ExampleTree(props) {
return (
<TreeView
aria-label="Example tree with dynamic content"
height="size-3000"
maxWidth="size-6000"
items={items}
{...props}
>
{(item: MyItem) => (
<TreeViewItem
childItems={item.childItems}
textValue={item.name}
>
<Text>{item.name}</Text>
{item.icon}
</TreeViewItem>
)}
</TreeView>
);
}
type MyItem = {
id: string;
name: string;
icon: JSX.Element;
childItems?: MyItem[];
};
let items: MyItem[] = [
{
id: 'projects',
name: 'Projects',
icon: <Folder />,
childItems: [
{
id: 'project-1',
name:
'Project 1',
icon: (
<FileTxt />
)
},
{
id: 'project-2',
name:
'Project 2',
icon: <Folder />,
childItems: [
{
id:
'document-a',
name:
'Document A',
icon: (
<FileTxt />
)
},
{
id:
'document-b',
name:
'Document B',
icon: (
<FileTxt />
)
}
]
}
]
},
{
id: 'reports',
name: 'Reports',
icon: <Folder />,
childItems: [
{
id: 'report-1',
name:
'Reports 1',
icon: (
<FileTxt />
)
}
]
}
];
function ExampleTree(
props
) {
return (
<TreeView
aria-label="Example tree with dynamic content"
height="size-3000"
maxWidth="size-6000"
items={items}
{...props}
>
{(
item: MyItem
) => (
<TreeViewItem
childItems={item
.childItems}
textValue={item
.name}
>
<Text>
{item.name}
</Text>
{item.icon}
</TreeViewItem>
)}
</TreeView>
);
}
Internationalization#
To internationalize a TreeView, all text content within the TreeView should be localized. This includes the aria-label
provided to the TreeView if any.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of TreeView is automatically flipped.
Labeling#
Accessibility#
An aria-label
must be provided to the TreeView for accessibility. If the TreeView is labeled by a separate element, an aria-labelledby
prop must be provided using the id of the labeling element instead.
Expansion#
By default, TreeView items are initially collapsed. Use defaultExpandedKeys
to provide a default set of expanded items. Note that the value of the expanded keys must match the id
prop of the TreeViewItem.
The example below uses defaultExpandedKeys
to select the items with keys "documents" and "photos".
<ExampleTree
aria-label="Example tree with default expanded items"
defaultExpandedKeys={['projects', 'reports']}/>
<ExampleTree
aria-label="Example tree with default expanded items"
defaultExpandedKeys={['projects', 'reports']}/>
<ExampleTree
aria-label="Example tree with default expanded items"
defaultExpandedKeys={[
'projects',
'reports'
]}/>
Controlled expansion#
To programmatically control item expansion, use the expandedKeys
prop paired with the onExpandedChange
callback. The key
prop from the expanded items will
be passed into the callback when the item is pressed, allowing you to update state accordingly.
Here is how you would control expansion for the above example.
function ControlledExpansion() {
let [expandedKeys, setExpandedKeys] = React.useState<Set<Key>>(
new Set(['projects', 'reports'])
);
return (
<ExampleTree
aria-label="Example tree with controlled expanded items"
expandedKeys={expandedKeys}
onExpandedChange={setExpandedKeys} />
);
}
function ControlledExpansion() {
let [expandedKeys, setExpandedKeys] = React.useState<
Set<Key>
>(new Set(['projects', 'reports']));
return (
<ExampleTree
aria-label="Example tree with controlled expanded items"
expandedKeys={expandedKeys}
onExpandedChange={setExpandedKeys} />
);
}
function ControlledExpansion() {
let [
expandedKeys,
setExpandedKeys
] = React.useState<
Set<Key>
>(
new Set([
'projects',
'reports'
])
);
return (
<ExampleTree
aria-label="Example tree with controlled expanded items"
expandedKeys={expandedKeys}
onExpandedChange={setExpandedKeys} />
);
}
Selection#
By default, TreeView doesn't allow item selection but this can be enabled using the selectionMode
prop.
Use defaultSelectedKeys
to provide a default set of selected items. Note that the value of the selected keys must match the id
prop of the TreeViewItem.
The example below enables multiple selection mode, and uses defaultSelectedKeys
to select the items with keys "document-a" and "document-b".
<ExampleTree
aria-label="Example tree with selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
defaultSelectedKeys={['document-a', 'document-b']}/>
<ExampleTree
aria-label="Example tree with selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
defaultSelectedKeys={['document-a', 'document-b']}/>
<ExampleTree
aria-label="Example tree with selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="multiple"
defaultSelectedKeys={[
'document-a',
'document-b'
]}/>
Controlled selection#
To programmatically control item selection, use the selectedKeys
prop paired with the onSelectionChange
callback. The key
prop from the selected items will
be passed into the callback when the item is pressed, allowing you to update state accordingly.
Here is how you would control selection for the above example.
import type {Selection} from '@adobe/react-spectrum';
function ControlledSelection() {
let [selectedKeys, setSelectedKeys] = React.useState<Selection>(
new Set(['document-a', 'document-b'])
);
return (
<ExampleTree
aria-label="Example tree with controlled selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys} />
);
}
import type {Selection} from '@adobe/react-spectrum';
function ControlledSelection() {
let [selectedKeys, setSelectedKeys] = React.useState<
Selection
>(new Set(['document-a', 'document-b']));
return (
<ExampleTree
aria-label="Example tree with controlled selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys} />
);
}
import type {Selection} from '@adobe/react-spectrum';
function ControlledSelection() {
let [
selectedKeys,
setSelectedKeys
] = React.useState<
Selection
>(
new Set([
'document-a',
'document-b'
])
);
return (
<ExampleTree
aria-label="Example tree with controlled selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="multiple"
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys} />
);
}
Single selection#
To limit users to selecting only a single item at a time, selectionMode
can be set to single
.
<ExampleTree
aria-label="Example tree with single selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"/>
<ExampleTree
aria-label="Example tree with single selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"/>
<ExampleTree
aria-label="Example tree with single selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="single"/>
Disallow empty selection#
TreeView also supports a disallowEmptySelection
prop which forces the user to have at least one item in the TreeView selected at all times.
In this mode, if a single item is selected and the user presses it, it will not be deselected.
<ExampleTree
aria-label="Example tree with disallowed empty selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"
defaultSelectedKeys={['document-a']}
disallowEmptySelection/>
<ExampleTree
aria-label="Example tree with disallowed empty selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"
defaultSelectedKeys={['document-a']}
disallowEmptySelection/>
<ExampleTree
aria-label="Example tree with disallowed empty selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="single"
defaultSelectedKeys={[
'document-a'
]}
disallowEmptySelection/>
Disabled items#
You can disable specific items by providing an array of keys to TreeView via the disabledKeys
prop. This will prevent items from being selectable as shown in the example below.
<ExampleTree
aria-label="Example tree with disabled items"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"
disabledKeys={['document-a', 'document-b']}/>
<ExampleTree
aria-label="Example tree with disabled items"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="single"
disabledKeys={['document-a', 'document-b']}/>
<ExampleTree
aria-label="Example tree with disabled items"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="single"
disabledKeys={[
'document-a',
'document-b'
]}/>
Highlight selection#
By default, TreeView uses the checkbox selection style, which includes a checkbox in each item for selection. When the selectionStyle prop is set to "highlight"
, the checkboxes are hidden,
and the selected items are displayed with a highlighted background instead.
In addition to changing the appearance, the selection behavior also changes depending on the selectionStyle
prop. In the default checkbox selection style, clicking, tapping, or pressing
the Space or Enter keys toggles selection for the focused item. Using the arrow keys moves focus but does not change selection.
In the highlight selection style, however, clicking a item with the mouse replaces the selection with only that item. Using the arrow keys moves both focus and selection. To select multiple items, modifier keys such as Ctrl, Cmd, and Shift can be used. On touch screen devices, selection always behaves as toggle since modifier keys may not be available.
These selection styles implement the behaviors defined in Aria Practices.
<ExampleTree
aria-label="Example tree with highlight selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
defaultSelectedKeys={['document-a', 'document-b']}
selectionStyle="highlight"/>
<ExampleTree
aria-label="Example tree with highlight selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
defaultSelectedKeys={['document-a', 'document-b']}
selectionStyle="highlight"/>
<ExampleTree
aria-label="Example tree with highlight selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="multiple"
defaultSelectedKeys={[
'document-a',
'document-b'
]}
selectionStyle="highlight"/>
Actions#
Item actions#
TreeView supports item actions via the onAction
prop, which is useful for functionality such as navigation. When nothing is selected, the TreeView performs actions by default when clicking or tapping a item.
Items may be selected using the checkbox, or by long pressing on touch devices. When at least one item is selected, the TreeView is in selection mode,
and clicking or tapping a item toggles the selection. Actions may also be triggered via the Enter key, and selection using the Space key.
This behavior is slightly different in the highlight selection style, where single clicking selects the item and actions are performed via double click. Touch and keyboard behaviors are unaffected.
<Flex direction="column" gap="size-300">
<ExampleTree
aria-label="Example tree with item actions and checkbox selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
onAction={key => alert(`Opening item ...`)} />
<ExampleTree
aria-label="Example tree with item actions and highlight selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
selectionStyle="highlight"
onAction={key => alert(`Opening item ...`)} />
</Flex>
<Flex direction="column" gap="size-300">
<ExampleTree
aria-label="Example tree with item actions and checkbox selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
onAction={(key) => alert(`Opening item ...`)} />
<ExampleTree
aria-label="Example tree with item actions and highlight selection"
defaultExpandedKeys={['projects', 'project-2']}
selectionMode="multiple"
selectionStyle="highlight"
onAction={(key) => alert(`Opening item ...`)} />
</Flex>
<Flex
direction="column"
gap="size-300"
>
<ExampleTree
aria-label="Example tree with item actions and checkbox selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="multiple"
onAction={(key) =>
alert(
`Opening item
...`)} />
<ExampleTree
aria-label="Example tree with item actions and highlight selection"
defaultExpandedKeys={[
'projects',
'project-2'
]}
selectionMode="multiple"
selectionStyle="highlight"
onAction={(key) =>
alert(
`Opening item
...`)} />
</Flex>
Links#
Tree items may also be links to another page or website. This can be achieved by passing the href
prop to the <TreeViewItem>
component. Links behave the same way as described above for item actions depending on the selectionMode
and selectionStyle
.
<TreeView
aria-label="Example tree with links"
defaultExpandedKeys={new Set(['bookmarks'])}
height="size-2000"
maxWidth="size-6000"
>
<TreeViewItem id="bookmarks" textValue="Bookmarks">
<Text>Bookmarks</Text>
<Folder />
<TreeViewItem
href="https://adobe.com/"
target="_blank"
id="adobe"
textValue="Adobe"
>
<Text>Adobe</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://google.com/"
target="_blank"
id="google"
textValue="Google"
>
<Text>Google</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://nytimes.com/"
target="_blank"
id="nytimes"
textValue="New York Times"
>
<Text>New York Times</Text>
<GlobeOutline />
</TreeViewItem>
</TreeViewItem>
</TreeView>
<TreeView
aria-label="Example tree with links"
defaultExpandedKeys={new Set(['bookmarks'])}
height="size-2000"
maxWidth="size-6000"
>
<TreeViewItem id="bookmarks" textValue="Bookmarks">
<Text>Bookmarks</Text>
<Folder />
<TreeViewItem
href="https://adobe.com/"
target="_blank"
id="adobe"
textValue="Adobe"
>
<Text>Adobe</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://google.com/"
target="_blank"
id="google"
textValue="Google"
>
<Text>Google</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://nytimes.com/"
target="_blank"
id="nytimes"
textValue="New York Times"
>
<Text>New York Times</Text>
<GlobeOutline />
</TreeViewItem>
</TreeViewItem>
</TreeView>
<TreeView
aria-label="Example tree with links"
defaultExpandedKeys={new Set(
['bookmarks']
)}
height="size-2000"
maxWidth="size-6000"
>
<TreeViewItem
id="bookmarks"
textValue="Bookmarks"
>
<Text>
Bookmarks
</Text>
<Folder />
<TreeViewItem
href="https://adobe.com/"
target="_blank"
id="adobe"
textValue="Adobe"
>
<Text>
Adobe
</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://google.com/"
target="_blank"
id="google"
textValue="Google"
>
<Text>
Google
</Text>
<GlobeOutline />
</TreeViewItem>
<TreeViewItem
href="https://nytimes.com/"
target="_blank"
id="nytimes"
textValue="New York Times"
>
<Text>
New York Times
</Text>
<GlobeOutline />
</TreeViewItem>
</TreeViewItem>
</TreeView>
Client side routing#
The <TreeViewItem>
component works with frameworks and client side routers like Next.js and React Router. As with other React Spectrum components that support links, this works via the Provider component at the root of your app. See the client side routing guide to learn how to set this up.
With action groups#
<TreeView
aria-label="Example tree with action groups"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem childItems={item.childItems} textValue={item.name}>
<Text>{item.name}</Text>
{item.icon}
<ActionGroup
onAction={(key) => alert(`Item: , Action: `)}
>
<Item key="edit" textValue="Edit">
<Edit />
<Text>Edit</Text>
</Item>
<Item key="delete" textValue="Delete">
<Delete />
<Text>Delete</Text>
</Item>
</ActionGroup>
</TreeViewItem>
)}
</TreeView>
<TreeView
aria-label="Example tree with action groups"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem
childItems={item.childItems}
textValue={item.name}
>
<Text>{item.name}</Text>
{item.icon}
<ActionGroup
onAction={(key) =>
alert(`Item: , Action: `)}
>
<Item key="edit" textValue="Edit">
<Edit />
<Text>Edit</Text>
</Item>
<Item key="delete" textValue="Delete">
<Delete />
<Text>Delete</Text>
</Item>
</ActionGroup>
</TreeViewItem>
)}
</TreeView>
<TreeView
aria-label="Example tree with action groups"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem
childItems={item
.childItems}
textValue={item
.name}
>
<Text>
{item.name}
</Text>
{item.icon}
<ActionGroup
onAction={(
key
) =>
alert(
`Item:
, Action: `)}
>
<Item
key="edit"
textValue="Edit"
>
<Edit />
<Text>
Edit
</Text>
</Item>
<Item
key="delete"
textValue="Delete"
>
<Delete />
<Text>
Delete
</Text>
</Item>
</ActionGroup>
</TreeViewItem>
)}
</TreeView>
With action menus#
<TreeView
aria-label="Example tree with action menus"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem childItems={item.childItems} textValue={item.name}>
<Text>{item.name}</Text>
{item.icon}
<ActionMenu
onAction={(key) => alert(`Item: , Action: `)}
>
<Item key="edit" textValue="Edit">
<Edit />
<Text>Edit</Text>
</Item>
<Item key="delete" textValue="Delete">
<Delete />
<Text>Delete</Text>
</Item>
</ActionMenu>
</TreeViewItem>
)}
</TreeView>
<TreeView
aria-label="Example tree with action menus"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem
childItems={item.childItems}
textValue={item.name}
>
<Text>{item.name}</Text>
{item.icon}
<ActionMenu
onAction={(key) =>
alert(`Item: , Action: `)}
>
<Item key="edit" textValue="Edit">
<Edit />
<Text>Edit</Text>
</Item>
<Item key="delete" textValue="Delete">
<Delete />
<Text>Delete</Text>
</Item>
</ActionMenu>
</TreeViewItem>
)}
</TreeView>
<TreeView
aria-label="Example tree with action menus"
height="size-3000"
maxWidth="size-6000"
items={items}
>
{(item: MyItem) => (
<TreeViewItem
childItems={item
.childItems}
textValue={item
.name}
>
<Text>
{item.name}
</Text>
{item.icon}
<ActionMenu
onAction={(
key
) =>
alert(
`Item:
, Action: `)}
>
<Item
key="edit"
textValue="Edit"
>
<Edit />
<Text>
Edit
</Text>
</Item>
<Item
key="delete"
textValue="Delete"
>
<Delete />
<Text>
Delete
</Text>
</Item>
</ActionMenu>
</TreeViewItem>
)}
</TreeView>
Props#
TreeView props#
Name | Type | Description |
renderEmptyState | () => JSX.Element | Provides content to display when there are no items in the tree. |
children | ReactNode | (
(item: object
)) => ReactNode | The contents of the tree. |
disabledBehavior | DisabledBehavior | Whether disabledKeys applies to all interactions, or only selection. |
items | Iterable<T> | Item objects in the collection. |
disabledKeys | Iterable<Key> | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. |
selectionMode | SelectionMode | The type of selection that is allowed in the collection. |
disallowEmptySelection | boolean | Whether the collection allows empty selection. |
selectedKeys | 'all' | Iterable<Key> | The currently selected keys in the collection (controlled). |
defaultSelectedKeys | 'all' | Iterable<Key> | The initial selected keys in the collection (uncontrolled). |
id | string | undefined | The element's unique identifier. See MDN. |
selectionStyle | 'checkbox' | 'highlight' | How selection should be displayed. |
expandedKeys | Iterable<Key> | The currently expanded keys in the collection (controlled). |
defaultExpandedKeys | Iterable<Key> | The initial expanded keys in the collection (uncontrolled). |
Events
Name | Type | Description |
onAction | (
(key: Key
)) => void | Handler that is called when a user performs an action on an item. The exact user event depends on
the collection's |
onSelectionChange | (
(keys: Selection
)) => void | Handler that is called when the selection changes. |
onExpandedChange | (
(keys: Set<Key>
)) => any | Handler that is called when items are expanded or collapsed. |
Layout
Name | Type | Description |
flex | Responsive<string
| number
| boolean> | When used in a flex layout, specifies how the element will grow or shrink to fit the space available. See MDN. |
flexGrow | Responsive<number> | When used in a flex layout, specifies how the element will grow to fit the space available. See MDN. |
flexShrink | Responsive<number> | When used in a flex layout, specifies how the element will shrink to fit the space available. See MDN. |
flexBasis | Responsive<number | string> | When used in a flex layout, specifies the initial main size of the element. See MDN. |
alignSelf | Responsive<'auto'
| 'normal'
| 'start'
| 'end'
| 'center'
| 'flex-start'
| 'flex-end'
| 'self-start'
| 'self-end'
| 'stretch'> | Overrides the alignItems property of a flex or grid container. See MDN. |
justifySelf | Responsive<'auto'
| 'normal'
| 'start'
| 'end'
| 'flex-start'
| 'flex-end'
| 'self-start'
| 'self-end'
| 'center'
| 'left'
| 'right'
| 'stretch'> | Specifies how the element is justified inside a flex or grid container. See MDN. |
order | Responsive<number> | The layout order for the element within a flex or grid container. See MDN. |
gridArea | Responsive<string> | When used in a grid layout, specifies the named grid area that the element should be placed in within the grid. See MDN. |
gridColumn | Responsive<string> | When used in a grid layout, specifies the column the element should be placed in within the grid. See MDN. |
gridRow | Responsive<string> | When used in a grid layout, specifies the row the element should be placed in within the grid. See MDN. |
gridColumnStart | Responsive<string> | When used in a grid layout, specifies the starting column to span within the grid. See MDN. |
gridColumnEnd | Responsive<string> | When used in a grid layout, specifies the ending column to span within the grid. See MDN. |
gridRowStart | Responsive<string> | When used in a grid layout, specifies the starting row to span within the grid. See MDN. |
gridRowEnd | Responsive<string> | When used in a grid layout, specifies the ending row to span within the grid. See MDN. |
Spacing
Name | Type | Description |
margin | Responsive<DimensionValue> | The margin for all four sides of the element. See MDN. |
marginTop | Responsive<DimensionValue> | The margin for the top side of the element. See MDN. |
marginBottom | Responsive<DimensionValue> | The margin for the bottom side of the element. See MDN. |
marginStart | Responsive<DimensionValue> | The margin for the logical start side of the element, depending on layout direction. See MDN. |
marginEnd | Responsive<DimensionValue> | The margin for the logical end side of an element, depending on layout direction. See MDN. |
marginX | Responsive<DimensionValue> | The margin for both the left and right sides of the element. See MDN. |
marginY | Responsive<DimensionValue> | The margin for both the top and bottom sides of the element. See MDN. |
Sizing
Name | Type | Description |
width | Responsive<DimensionValue> | The width of the element. See MDN. |
minWidth | Responsive<DimensionValue> | The minimum width of the element. See MDN. |
maxWidth | Responsive<DimensionValue> | The maximum width of the element. See MDN. |
height | Responsive<DimensionValue> | The height of the element. See MDN. |
minHeight | Responsive<DimensionValue> | The minimum height of the element. See MDN. |
maxHeight | Responsive<DimensionValue> | The maximum height of the element. See MDN. |
Positioning
Name | Type | Description |
position | Responsive<'static'
| 'relative'
| 'absolute'
| 'fixed'
| 'sticky'> | Specifies how the element is positioned. See MDN. |
top | Responsive<DimensionValue> | The top position for the element. See MDN. |
bottom | Responsive<DimensionValue> | The bottom position for the element. See MDN. |
left | Responsive<DimensionValue> | The left position for the element. See MDN. Consider using start instead for RTL support. |
right | Responsive<DimensionValue> | The right position for the element. See MDN. Consider using start instead for RTL support. |
start | Responsive<DimensionValue> | The logical start position for the element, depending on layout direction. See MDN. |
end | Responsive<DimensionValue> | The logical end position for the element, depending on layout direction. See MDN. |
zIndex | Responsive<number> | The stacking order for the element. See MDN. |
isHidden | Responsive<boolean> | Hides the element. |
Accessibility
Name | Type | Description |
aria-label | string | Defines a string value that labels the current element. |
aria-labelledby | string | Identifies the element (or elements) that labels the current element. |
aria-describedby | string | Identifies the element (or elements) that describes the object. |
aria-details | string | Identifies the element (or elements) that provide a detailed, extended description for the object. |
Advanced
Name | Type | Description |
UNSAFE_className | string | Sets the CSS className for the element. Only use as a last resort. Use style props instead. |
UNSAFE_style | CSSProperties | Sets inline style for the element. Only use as a last resort. Use style props instead. |
TreeViewItem props#
Name | Type | Description |
children | ReactNode | Rendered contents of the tree item or child items. |
textValue | string | A string representation of the tree item's contents, used for features like typeahead. |
hasChildItems | boolean | Whether this item has children, even if not loaded yet. |
childItems | Iterable<object> | A list of child tree item objects used when dynamically rendering the tree item children. |
id | Key | The unique id of the tree row. |
href | Href | A URL to link to. See MDN. |
hrefLang | string | Hints at the human language of the linked URL. SeeMDN. |
target | HTMLAttributeAnchorTarget | The target window for the link. See MDN. |
rel | string | The relationship between the linked resource and the current page. See MDN. |
download | boolean | string | Causes the browser to download the linked URL. A string may be provided to suggest a file name. See MDN. |
ping | string | A space-separated list of URLs to ping when the link is followed. See MDN. |
referrerPolicy | HTMLAttributeReferrerPolicy | How much of the referrer to send when following the link. See MDN. |
routerOptions | RouterOptions | Options for the configured client side router. |
Accessibility
Name | Type | Description |
aria-label | string | An accessibility label for this tree item. |
Visual options#
Empty state#
Use the renderEmptyState
prop to customize what the TreeView will display if there are no items provided.
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';
import {Heading} from '@react-spectrum/text';
function renderEmptyState() {
return (
<IllustratedMessage>
<NotFound />
<Heading>No results</Heading>
<Content>No results found</Content>
</IllustratedMessage>
);
}
<TreeView
aria-label="Example tree for empty state"
height="size-2400"
maxWidth="size-6000"
renderEmptyState={renderEmptyState}
>
{[]}
</TreeView>
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';
import {Heading} from '@react-spectrum/text';
function renderEmptyState() {
return (
<IllustratedMessage>
<NotFound />
<Heading>No results</Heading>
<Content>No results found</Content>
</IllustratedMessage>
);
}
<TreeView
aria-label="Example tree for empty state"
height="size-2400"
maxWidth="size-6000"
renderEmptyState={renderEmptyState}
>
{[]}
</TreeView>
import {Content} from '@react-spectrum/view';
import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
import NotFound from '@spectrum-icons/illustrations/NotFound';
import {Heading} from '@react-spectrum/text';
function renderEmptyState() {
return (
<IllustratedMessage>
<NotFound />
<Heading>
No results
</Heading>
<Content>
No results found
</Content>
</IllustratedMessage>
);
}
<TreeView
aria-label="Example tree for empty state"
height="size-2400"
maxWidth="size-6000"
renderEmptyState={renderEmptyState}
>
{[]}
</TreeView>
Testing#
The TreeView features long press interactions on its items depending on the item actions provided and if user is interacting with the list on a touch device. Please see the following sections in the testing docs for more information on how to handle these behaviors in your test suite.
Please also refer to React Spectrum's test suite if you find that the above isn't sufficient when resolving issues in your own test cases.