TreeView
TreeView is a hierarchical list of items that may have a parent-child relationship where children can be toggled into view by expanding or collapsing their parent item.
Page navigation navigation
Behavioral expectations
The TreeView replicates the experience of an operating system's file explorer capabilities. It is designed to allow a user to navigate and take action on groups of items listed in a hierarchical format. This is a different experience than website navigation, which has a different mental model, operational requirements, and usability expectations.
Label
TreeViews need an accessible name to be supplied, ideally via aria-labelledby pointing at an appropriate heading before the tree. If the TreeView has enough surrounding context that it doesn't need a visible label, apply sr-only to the heading to hide it visually, but preserve the underlying programatic association.
Edit in FigmaKeyboard navigation
| Key(s) | Description |
|---|---|
| Enter | Performs the default action (e.g. onclick event) for the focused node which is to activate the link. |
| Tab | Moves focus outside of the TreeView to the next focusable node. |
| ArrowDown |
|
| ArrowUp |
|
| ArrowRight |
|
| ArrowLeft |
|
| Home | Moves focus to first node without opening or closing a node. |
| End | Moves focus to the last node that can be focused without expanding any nodes that are closed. |
| a-z, A-Z, all printable characters |
|
Typeahead behavior
Focus moves to the next node with a name that starts with the typed character(s). Wait for 300ms from the last key press to stop searching.
Typeahead behavior is case insensitive, and any printable character can be used, not just alphanumeric characters.
The Space key is ignored because it's being reserved for toggling a TreeView node's checkbox. Nodes with checkboxes are not supported yet, but they may in the future.
Focus behavior
Focus in
If moving focus into the TreeView for the first time, focus on the first node.
If moving focus back into the TreeView after the user already interacted with it, focus the previously focused TreeView node.
Focus out
If activating a node causes new content to appear without a page refresh, focus should be moved to the new content. By default, focus should be moved to the first focusable control within the main content region. We should avoid skipping any content so that the user can easily go back to the TreeView if they activate a node by accident.
If the first focusable element would cause a confusing experience for folks who listen to content using a screen reader, then an alternate element may be defined
Minimum click target area for the chevron
The chevron has a generous click area to make it an easier target to hit, but it's kept compact to preserve horizontal space in deeply nested nodes.
When we detect that the user is on a device with a coarse pointer, the click target is enlarged.
Edit in FigmaAccessibility and usability expectations
Presentation
Cognition
- The tree structure should aid navigation, instead of making the structure more difficult to find things
- Leading and trailing visuals must be used consistently for all nodes, or not at all
Vision
- When using leading and trailing visuals, ensure that they have a color contrast ratio of at least 3:1 against the node’s background color
- Ensure that action identifiers, such as chevrons for expanding/collapsing content, have a color contrast ratio of at least 3:1 against the node’s background color
- Ensure that node text has a color contrast ratio of at least 4.5:1
- Ensure that the current node communicates that it is the current item, in a way that doesn’t rely on color alone, and that the identifier has a color contrast ratio of at least 3:1 against the tree’s background color
Mobility
- Every node, as well as every leading action, must have a minimum target size of 24 by 24 CSS pixels. This is to ensure that the control is large enough to be easily activated by users with moving disabilities
Adaptability
- Make sure that node labels can be increased up to 200%, and remain fully visible
- Every node label must remain readable and not require horizontal scrolling to read it or operate it, at a viewport size of 320 by 256 CSS pixels
- When adding additional text spacing, make sure that all node labels can still be read in their entirety
Interaction
Keyboard
- If the component has not yet received focus, when navigating to it with the
Tabkey, the first node should receive focus. If the component has already received focus, the last interacted with node should receive focus, when navigating back to the component with theTabkey - It must be possible to navigate through the items in the tree view using the up and down arrow keys
- It must be possible to expand a parent node, or jump back to a child node’s parent node using the left and right arrow keys
- It must be possible to navigate to the first and last node in the component using the
HomeandEndkeys respectively - It must be possible to move focus to the next node that matches the single character keys entered while the component has focus
- Nodes must receive focus in a logical order, which in the majority of cases, will be in the order that they are visually displayed
- Collapsed nodes that are visually hidden, must not receive focus
- Nodes featuring a leading action, such as drag and drop, must receive focus and be interactive with only a keyboard
Touch and mouse
- Expanding/collapsing parent nodes, and any leading actions, must be activated on the up event, and not the down event, or there must be a way to prevent the interaction from taking place on the down event
Engineering for compatibility with assistive technology
Screen reader
- The order in which the TreeView nodes are implemented should result in a logical reading order
- The level of the node should be communicated, as well as the position of the node within the level (e.g. level 2, node 1 of 3)
- A parent node’s grouping must be communicated, along with the group name, to allow people to understand the structure of the items
- The state of parent nodes must be communicated, informing people as to whether nested groups are expanded or collapsed
- Selected and currently active nodes must programmatically convey when they are selected
- Each item in the tree should have a
roleoftreeitem, to convey that it is a node
Speech recognition
- All nodes must include the visible node label in their accessible name
- Leading actions and any secondary actions should also include the visible label in their accessible names, to help people using voice control software to interact with them
Built-in accessibility features
This component is rendered as a tree, with the required group and treeitem roles provided automatically, based on the structure of <TreeView.SubTree> and <TreeView.Item> elements. Similarly, the required aria-level, aria-expanded, and aria-selected attributes are also applied automatically, depending on the structure of the tree, and the current state of the nodes.
Along with this, regardless of the structure, focus management is handled with the addition of tabindex=“-1” attributes, ensuring that there is only a single tabstop for the component. Keyboard navigation is then provided with additional scripting to ensure that the component can be used with only a keyboard.
<ul role="tree" aria-label="Files changed" …>
<li
…
tabindex="-1"
id="parent-node-one"
role="treeitem"
aria-labelledby="«r1fe»"
aria-level="1"
aria-expanded="true"
aria-selected="false"
>
<div …>
<div …>
<div …></div>
</div>
<div …><svg aria-hidden="true" …>…</svg></div>
<div id="«r1fe»" …>
<span …>Parent node</span>
</div>
</div>
<ul role="group" aria-label="Parent node" …>
<li
…
tabindex="-1"
id="child-node-one"
role="treeitem"
aria-labelledby="«r1fh»"
aria-level="2"
aria-selected="false"
>
<div …>
<div …>
<div …>
<div …></div>
</div>
</div>
<div id="«r1fh»" …>
<span …>Child node one</span>
</div>
</div>
</li>
…
</ul>
</li>
…
</ul>
Implementation requirements
The TreeView component must be given a group label to help convey the purpose of the component, and provide context as to what the different groups and tree-items relate to.
This can be achieved in a few different ways:
If there’s already a visible label that relates to the <TreeView> component, use the aria-labelledby prop to reference the id of the visible label. For example:
<label id="repo-files-label" …>Repo files</label>
<TreeView aria-labelledby="repo-files-label" …>
…
This can also be achieved using an sr-only heading, as mentioned earlier: Label
For the <TreeView.Item>, while an aria-label and aria-labelledby prop can be used to change the accessible name of the node, ensure that the new accessible name includes the visible node label text. This way, people using voice control software will still be able to easily interact with the node. If you want to add supplemental information to the accessible name, we recommend that you do this after the visible node label text.
Leading visuals and trailing visuals
If you add icons/graphics that provide information visually, ensure that you also provide a text alternative for these with a label.
Using the Diff icons as an example: visually, these convey how a file has changed, so we need to make sure that we provide text alternatives for them using the label prop.
<TreeView.TrailingVisual label="Added">
<DiffAddedIcon fill="var(--fgColor-success)" />
</TreeView.TrailingVisual>
…
<TreeView.TrailingVisual label="Modified">
<DiffModifiedIcon fill="var(--fgColor-attention)" />
</TreeView.TrailingVisual>
Customising the display of the component
Using the TreeView component’s truncate and className props, it’s possible to change the style and therefore the display of the component. When doing this, make sure that:
- content is not further truncated, and therefore lost, when zooming in to 200% or adding additional text spacing
- node label text has a contrast of at least 4.5:1 against the node’s background
- node leading or trailing icons have a contrast of at least 3:1 against the tree’s background
How to test the component
Integration tests
- If the TreeViews’s node label text is visible at wide viewports, ensure that it is not hidden or truncated at narrow viewports
- If activating a node causes new content to appear without a page refresh, focus should be moved to the first interactive element in the new content
Component tests
- The TreeViews component is exposed as an unordered list element (
<ul>) with a role oftree, and an appropriate accessible name - Each node is exposed as a
treeitem, with an appropriate accessible name - Where a node has a leading or trailing visual, if the visual conveys important information, it must have a text alternative to provide equivalent information
- The selected node has an
aria-current=“true”attribute - Each node, their leading actions or secondary actions, all meet the minimum target size requirement of 24 by 24 CSS pixels
- Parent
<TreeView.Item>elements have anaria-expandedattribute set tofalsewhen collapsed, andtruewhen expanded <TreeView.SubTree>’s are exposed as a role ofgroupand use the previous node’s label as their accessible name<TreeView.Item>elements within a<TreeView.SubTree>have an appropriatearia-levelattribute- Only one node receives focus, while the rest have a
tabindex=“-1”attribute, to reduce the number of tabstops - Nodes only have a single leading action, for expanding/collapsing them, and no other secondary actions