Last active
March 12, 2023 11:28
-
-
Save bvaughn/886c028832100eae1df8236b56a8c02b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function setFocusIfFocusable(node) { | |
if (node.nodeType !== Node.ELEMENT_NODE) { | |
// Text and comment nodes aren't focusable. | |
return false; | |
} | |
if (node.disabled === true) { | |
// Disabled elements can't be focused. | |
return false; | |
} | |
if (node.tabIndex < 0) { | |
// The HTML spec says that negative tab index values indicate an element should be, | |
// "click focusable but not sequentially focusable". | |
// https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute | |
// | |
// The HTML focusable spec also says, | |
// "User agents should consider focusable areas with non-null tabindex values to be click focusable." | |
// https://html.spec.whatwg.org/multipage/interaction.html#focusable | |
// | |
// Despite this, it seems like some browsers (e.g. Chrome, Firefox) return -1 even for elements | |
// that don't accept focus, like HTMLImageElement or the outermost HTMLElement tag. | |
// I think this method should (at least for now) only concern itself with "sequentially focusable" elements. | |
// https://html.spec.whatwg.org/multipage/interaction.html#sequentially-focusable | |
return false; | |
} | |
if (node.offsetWidth === 0 || node.offsetHeight === 0) { | |
// Hidden items can't be focused. | |
return false; | |
} | |
// At this point we assume the element accepts focus, so let's try and see. | |
// Listen for a "focus" event to verify that focus was set. | |
// We could compare the node to document.activeElement after focus, | |
// but this would not handle the case where application code managed focus to automatically blur. | |
let didFocus = false; | |
const handleFocus = () => { | |
didFocus = true; | |
}; | |
try { | |
node.addEventListener('focus', handleFocus); | |
node.focus(); | |
} finally { | |
node.removeEventListener('focus', handleFocus); | |
} | |
return didFocus; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment