If you create JavaScript widgets, one of the key parts to accessibility is managing focus.
To manage focus, you need to find keyboard-focusable elements.
When you know the contents
It’s easy to find keyboard-focusable elements if you know the contents of the element beforehand.
For example, I know the focusable elements in this modal are <input>
and <button>
.
I can get the focusable elements with querySelectorAll
.
const focusableElements = [...modal.querySelectorAll('input, button')]
When you don’t know the contents
It’s harder to find keyboard-focusable elements if you don’t know the content beforehand.
After some research, I realised you could only focus on these elements with a keyboard:
<a>
<button>
<input>
<textarea>
<select>
<details>
- Elements with
tabindex
set to0
- Elements with
tabindex
set to a positive number
We can get all keyboard-focusable elements with the following querySelectorAll
. It looks a little complicated, but there’s no other way to include everything:
const keyboardfocusableElements = document.querySelectorAll(
'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'
)
Some elements (like button
) can be disabled. Disabled elements are not focusable. We can remove these elements with filter
.
const keyboardfocusableElements = [...document.querySelectorAll(
'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'
)]
.filter(el => !el.hasAttribute('disabled'))
Turning it into a function
This querySelectorAll
code is hard to read. We can put the entire thing into a function to make it more understandable.
/**
* Gets keyboard-focusable elements within a specified element
* @param {HTMLElement} [element=document] element
* @returns {Array}
*/
function getKeyboardFocusableElements (element = document) {
return [...element.querySelectorAll(
'a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'
)]
.filter(el => !el.hasAttribute('disabled'))
}