Skip to Content
Component ExamplesTree View

Overview

A tree view presents hierarchical data as an expandable and collapsible structure. The most common mistake is building trees from nested <ul> lists with click handlers on generic elements. These miss the required ARIA tree roles, expanded/collapsed states, level information, and keyboard navigation that screen reader and keyboard users depend on.

WCAG Criteria:

Key requirements:

  • The container needs role="tree" with an accessible label
  • Each item needs role="treeitem" with aria-level, aria-setsize, and aria-posinset
  • Parent nodes need aria-expanded="true" or "false" — leaf nodes must NOT have aria-expanded
  • Child groups are wrapped in an element with role="group"
  • Use roving tabindex — the focused item has tabindex="0", all others have tabindex="-1"
  • Arrow keys: Up/Down move between visible items, Right expands or moves to first child, Left collapses or moves to parent
  • Home/End jump to the first/last visible item in the tree
  • Enter/Space activate the current item

File Browser Tree

Accessible Tree View vs. Unsemantic Nested Lists

Inaccessible
<!-- No tree roles, no aria-expanded, no keyboard navigation --> <div class="file-tree"> <ul> <li> <span class="folder" onclick="toggleFolder(this)"> Documents </span> <ul style="margin-left: 20px"> <li><span>Resume.pdf</span></li> <li><span>Cover Letter.docx</span></li> </ul> </li> <li> <span class="folder" onclick="toggleFolder(this)"> Images </span> <ul style="margin-left: 20px; display: none"> <li><span>Photo.jpg</span></li> </ul> </li> </ul> </div>
Live Preview
Files
  • 📁 Documents
    • 📄 Resume.pdf
    • 📄 Cover Letter.docx
  • 📁 Images
    • 📸 Photo.jpg
Accessible
<ul role="tree" aria-label="File browser"> <li role="treeitem" aria-expanded="true" aria-level="1" aria-setsize="2" aria-posinset="1" tabindex="0"> Documents <ul role="group"> <li role="treeitem" aria-level="2" aria-setsize="2" aria-posinset="1" tabindex="-1"> Resume.pdf </li> <li role="treeitem" aria-level="2" aria-setsize="2" aria-posinset="2" tabindex="-1"> Cover Letter.docx </li> </ul> </li> <li role="treeitem" aria-expanded="false" aria-level="1" aria-setsize="2" aria-posinset="2" tabindex="-1"> Images <ul role="group" hidden> <li role="treeitem" aria-level="2" aria-setsize="1" aria-posinset="1" tabindex="-1"> Photo.jpg </li> </ul> </li> </ul> <script> // Roving tabindex: focused item tabindex="0", rest "-1" // ArrowDown/Up: move between visible treeitems // ArrowRight: expand closed node or move to first child // ArrowLeft: collapse open node or move to parent // Home/End: first/last visible item // Enter/Space: activate (toggle expand/collapse) </script>
Live Preview
Files
  • 📁 Documents
    • 📄 Resume.pdf
    • 📄 Cover Letter.docx

What’s wrong with the unsemantic nested lists?

  • No role="tree" on the container — screen readers cannot identify the widget as a tree
  • List items have no role="treeitem" — their hierarchical role is invisible to assistive technology
  • No aria-expanded on folders — users cannot tell whether a node is open or closed
  • No aria-level, aria-setsize, or aria-posinset — the nesting depth and position are not conveyed
  • No keyboard navigation — arrow keys do not work, so keyboard-only users are stranded
  • Indentation is purely visual (CSS margin) — the hierarchy is lost for non-visual users

What the screen reader announces:

VersionAnnouncement
Inaccessible (plain list)“Documents” — no role, no state, no tree context
Accessible (tree)“Documents, tree item, expanded, level 1, 1 of 2, File browser tree”
Collapsed folder”Images, tree item, collapsed, level 1, 2 of 2”
Leaf item focused”Resume.pdf, tree item, level 2, 1 of 2” — no expanded state announced
After collapsing”Documents, tree item, collapsed, level 1, 1 of 2”

Key teaching points:

  • Roving tabindex, not aria-activedescendant — roving tabindex (moving tabindex="0" to the active item and setting all others to tabindex="-1") provides more reliable VoiceOver support than aria-activedescendant
  • Never add aria-expanded to leaf nodes — only parent items that can be expanded or collapsed should have aria-expanded. Adding it to leaf nodes falsely tells screen readers the item has children
  • Right/Left arrows for expand/collapse — this is the expected keyboard convention for trees. Right arrow expands a closed node or moves to its first child; Left arrow collapses an open node or moves to its parent

Resources