diff --git a/src/helpers/scopeTab.js b/src/helpers/scopeTab.js index d152951b..1e24378a 100644 --- a/src/helpers/scopeTab.js +++ b/src/helpers/scopeTab.js @@ -1,5 +1,11 @@ import findTabbable from "./tabbable"; +function getActiveElement(el = document) { + return el.activeElement.shadowRoot + ? getActiveElement(el.activeElement.shadowRoot) + : el.activeElement; +} + export default function scopeTab(node, event) { const tabbable = findTabbable(node); @@ -14,19 +20,20 @@ export default function scopeTab(node, event) { const shiftKey = event.shiftKey; const head = tabbable[0]; const tail = tabbable[tabbable.length - 1]; + const activeElement = getActiveElement(); // proceed with default browser behavior on tab. // Focus on last element on shift + tab. - if (node === document.activeElement) { + if (node === activeElement) { if (!shiftKey) return; target = tail; } - if (tail === document.activeElement && !shiftKey) { + if (tail === activeElement && !shiftKey) { target = head; } - if (head === document.activeElement && shiftKey) { + if (head === activeElement && shiftKey) { target = tail; } @@ -57,7 +64,7 @@ export default function scopeTab(node, event) { // the focus if (!isSafariDesktop) return; - var x = tabbable.indexOf(document.activeElement); + var x = tabbable.indexOf(activeElement); if (x > -1) { x += shiftKey ? -1 : 1; diff --git a/src/helpers/tabbable.js b/src/helpers/tabbable.js index ff462c22..dc2d3d42 100644 --- a/src/helpers/tabbable.js +++ b/src/helpers/tabbable.js @@ -38,7 +38,11 @@ function visible(element) { let rootNode = element.getRootNode && element.getRootNode(); while (parentElement) { if (parentElement === document.body) break; - if (rootNode && parentElement === rootNode) parentElement = rootNode.host; + + // if we are not hidden yet, skip to checking outside the Web Component + if (rootNode && parentElement === rootNode) + parentElement = rootNode.host.parentNode; + if (hidesContents(parentElement)) return false; parentElement = parentElement.parentNode; } @@ -61,5 +65,14 @@ function tabbable(element) { } export default function findTabbableDescendants(element) { - return [].slice.call(element.querySelectorAll("*"), 0).filter(tabbable); + const descendants = [].slice + .call(element.querySelectorAll("*"), 0) + .reduce( + (finished, el) => [ + ...finished, + ...(!el.shadowRoot ? [el] : findTabbableDescendants(el.shadowRoot)) + ], + [] + ); + return descendants.filter(tabbable); }