I am looking for solution which allow to focus elements inside treeview using arrow keys.
Currently, I have treeView (ul) and treeNode (li). Each treeNode may have their own treeView and so on. Every treeNode has tabIndex="0"
property to add possibility navigate trough the treeView using Tab
key. It works fine. But I would like to add keyboard arrow support to do the same thing.
Any idea how to do this? P.S. I don't want to use any 3rd party libs expect pure React, JS.
<section>
<header>
{ title }
</header>
<ul>
<li>
<section>
<header>
{ title }
</header>
<ul>
// etc.
</ul>
</section>
</li>
</ul>
<section>
I am looking for solution which allow to focus elements inside treeview using arrow keys.
Currently, I have treeView (ul) and treeNode (li). Each treeNode may have their own treeView and so on. Every treeNode has tabIndex="0"
property to add possibility navigate trough the treeView using Tab
key. It works fine. But I would like to add keyboard arrow support to do the same thing.
Any idea how to do this? P.S. I don't want to use any 3rd party libs expect pure React, JS.
<section>
<header>
{ title }
</header>
<ul>
<li>
<section>
<header>
{ title }
</header>
<ul>
// etc.
</ul>
</section>
</li>
</ul>
<section>
Share
Improve this question
asked Jun 28, 2017 at 14:38
Roman MahotskyiRoman Mahotskyi
6,6858 gold badges49 silver badges93 bronze badges
2 Answers
Reset to default 5I have found a solution to move focus within treeView.
First of all you should find all your nodes inside your tree.
Then you can find focused element using document.activeElement
. After that, you be able to find this item within your array nodes. (document.activeElement == nodes[i]
) and remember index i
. To move focus using arrow keys, just add eventListener
to your node and handle it.
For example, to move upward you can do something like this:
if(arrowUp) { elements[i + 1].focus() }
Roman's answer is helpful. I took this a step further by creating functions that handle moving focus up or down.
In the ponent I have my handleKeyDown function called on the onKeyDown event:
<UnorderedList id='unordered-list' onKeyDown={handleKeyDown} />
To call the functions I used an if statement like this below in my onKeyDown handler:
const handleKeyDown = (e) => {
if(e.key === 'ArrowDown') {
moveFocusDown()
}
if(e.key === 'ArrowUp') {
moveFocusUp()
}
}
Next for the moveFocusDown function, I did the following:
const moveFocusDown = () => {
const listItems = document.querySelector('#unordered-list').childNodes
const activeItem = document.activeElement
for(let i = 0; i < listItems.length; i++) {
const listLength = listItems.length
if(activeItem === listItems[i] && activeItem !== listItems[listLength - 1]) {
listItems[i + 1].focus()
}
}
}
The conditional activeItem === listItems[i] && activeItem !== listItems[listLength - 1]
checks that the activeItem and the current index of the Unordered List child nodes are the same, then checks that the last element in the node list isn't the active element. This is needed to prevent moving focus to an element that doesn't exist.
The moveFocus up function is a little simpler:
const moveFocusUp = () => {
const listItems = document.querySelector('#menu').childNodes
const activeItem = document.activeElement
for(let i = 0; i < listItems.length; i++) {
if(activeItem === listItems[i] && activeItem !== listItems[0]) {
listItems[i - 1].focus()
}
}
}