Skip to content

Commit

Permalink
fix(tab): Keep focus on the document if there are no focusable elements
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanismaking committed Mar 20, 2020
1 parent 38e3c22 commit 420ae03
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
10 changes: 10 additions & 0 deletions __tests__/react/tab.js
Expand Up @@ -265,3 +265,13 @@ it("should not focus disabled elements", () => {
userEvent.tab();
expect(five).toHaveFocus();
});

it("should keep focus on the document if there are no enabled, focusable elements", () => {
render(<button disabled>no clicky</button>);

userEvent.tab();
expect(document.body).toHaveFocus();

userEvent.tab({ shift: true });
expect(document.body).toHaveFocus();
});
23 changes: 16 additions & 7 deletions src/index.js
Expand Up @@ -245,10 +245,16 @@ const userEvent = {
"input, button, select, textarea, a[href], [tabindex]"
);

let list = Array.prototype.filter
.call(focusableElements, function(item) {
return item.getAttribute("tabindex") !== "-1" && !item.disabled;
})
const enabledElements = Array.prototype.filter.call(
focusableElements,
function(el) {
return el.getAttribute("tabindex") !== "-1" && !el.disabled;
}
);

if (enabledElements.length === 0) return;

const orderedElements = enabledElements
.map((el, idx) => ({ el, idx }))
.sort((a, b) => {
const tabIndexA = a.el.getAttribute("tabindex");
Expand All @@ -259,12 +265,15 @@ const userEvent = {
return diff !== 0 ? diff : a.idx - b.idx;
});

const index = list.findIndex(({ el }) => el === document.activeElement);
const index = orderedElements.findIndex(
({ el }) => el === document.activeElement
);

let nextIndex = shift ? index - 1 : index + 1;
let defaultIndex = shift ? list.length - 1 : 0;
let defaultIndex = shift ? orderedElements.length - 1 : 0;

const { el: next } = list[nextIndex] || list[defaultIndex];
const { el: next } =
orderedElements[nextIndex] || orderedElements[defaultIndex];

if (next.getAttribute("tabindex") === null) {
next.setAttribute("tabindex", "0"); // jsdom requires tabIndex=0 for an item to become 'document.activeElement' (the browser does not)
Expand Down

0 comments on commit 420ae03

Please sign in to comment.