3 ms·
This is not what is typically called a tree view: this is collapsible nested lists. The differences are important, and very fiddly to reconcile. The key differ
by chrismorgan 4y ago
This is not what is typically called a tree view: this is collapsible nested lists. The differences are important, and very fiddly to reconcile.
The key difference is that in a tree view, every node is focusable and has an action associated with activating it (which for parent nodes might be expanding/collapsing, but need not be), whereas with collapsible nested lists, only parent nodes are focusable, and their action is reserved and limited to expanding and collapsing. (You could make leaf nodes focusable and give them actions—e.g. make each one a link—but you can’t give parent nodes any other action, which is a fundamental limitation.)
Here’s what tree views are: https://w3c.github.io/aria-practices/#TreeView https://w3c.github.io/aria-practices/#TreeView. This describes the functionality and interaction modes (including all the expected keyboard behaviours), with examples.
One important secondary difference: the article said that “the standard keyboard interaction is supported automatically”, and this is true for collapsible nested lists, but false for a tree view. In the former, each parent node is separately focusable, and you expect to use Tab/Shift+Tab to navigate between parent nodes; but tree views are composite widgets that manage focus, only appearing once in the tab order and using other keys (like the arrow keys) to manipulate focus within.
Is it possible to implement a true tree view with <details>? Mostly, yes, but there are limitations and difficulties.
If you’re OK with parent nodes’ only action being to toggle expansion, it’s not particularly hard; do it largely as shown in this article, making each leaf node focusable, and add some (nicely optional) JavaScript to get the keyboard interactions right and give the right ARIA attributes. The ARIA Authoring Practices document already linked will guide you through approximately all of the considerations. (If you haven’t worked with this document before, please do read the “Read Me First” section first.) In fact, I strongly recommend this general approach: make something that functions with only the HTML, then enhance it with JavaScript.
If you want parent nodes to have actions, parent nodes’ actions will need to be moved out of the <summary>. You’ll end up with something like this:
<ul class="tree">
<li>
<a href>Giant planets</a>
<details open>
<summary>Expand</summary>
<ul>
<li>
<a href>Gas giants</a>
<details>
<summary>Expand</summary>
<ul>
<li><a href>Jupiter</a></li>
<li><a href>Saturn</a></li>
</ul>
</details>
</li>
<li>
<a href>Ice giants</a>
<details>
<summary>Expand</summary>
<ul>
<li><a href>Uranus</a></li>
<li><a href>Neptune</a></li>
</ul>
</details>
</li>
</ul>
</details>
</li>
</ul>
Focus and accessibility management will become a little more complicated, but it’s still workable. But styling will be at least somewhat painful because of the DOM structures and the order of things. You’ll probably want to use details::before for the marker. Grid and `details { display: contents }` might help with layout, though absolute positioning is probably the pragmatic approach (and test cross-browser before doing anything like `details { display: contents }`, the two features can have surprising interactions). Also in the absence of JavaScript, it’s not going to be possible to get the expected interaction order: you would want the focus order to be expand/collapse button, then the node itself, then children, but those first two will necessarily be transposed. Still, it’ll be better than it not working at all.