The ARIA tree spec says that when the tree widget gets keyboard focus, then the first item should get focus (if no element has focus).
I have implemented this behavior below, but when my click handler fires I get a flash of focus on the first element...
How do I prevent this? (this is in the context of svelte if that matters..)
function ariaTree(node) { const selectable = node.querySelectorAll('.leaf, summary') function clickHandler(e) { selectable.forEach(item => item.classList.remove('selected')) e.target.classList.add('selected') } selectable.forEach(item => { item.addEventListener('click', clickHandler) }) // https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ // ..when a .. tree receives focus .. if no node is focused .. // select the first node. node.addEventListener('focusin', e => { if (node.querySelectorAll('.selected').length === 0) { e.preventDefault() // prevent giving focus to the first "button"-like element selectable[0].classList.add('selected') } }) //return {destroy() {...}} } ariaTree(document.querySelector('ul[role="tree"]'))
.wrapper { display: flex;&>* {flex: 1} } ul[role=tree] li { list-style-type: none } .selected { background-color: green; color: white; } :where(.leaf, summary):hover { background-color: navy; color: white; }
<div class="wrapper"><p> Preceeding element to the tree widget...<br> Press F7 to enable caret browsing (will display a cursor where the current keyboard focus is), click inside this text, then tab to get to the tree widget (the first item should get selection/focus).<br><br> Refresh the page (so no item in the tree widget has focus), then click on the last element (world). There is a flash of focus on the first element...</p><ul role="tree" tabindex="0"><li class="leaf"> hello</li><li class="branch"><details open><summary>beautiful</summary><ul><li class="leaf">world</li></ul></details></li></ul></div>