Document body should be a focusable element
See original GitHub issue@testing-library/user-event
version:@testing-library/user-event@10.4.0
- Testing Framework and version:
jest@25.1.0
- DOM Environment:
jsdom@16.2.0
- node:
node/10.20.1
Relevant code or config (I’m also using React)
it('manages the page tab sequence', () => {
function TestComponent() {
return (<ul role="listbox">
<li role="option" tabindex="0">First option</li>
<li role="option" tabindex="-1">Second option</li>
</ul>);
}
render(<TestComponent />);
expect(document.body).toHaveFocus();
userEvent.tab();
expect(screen.getByText('First option')).toHaveFocus();
userEvent.tab();
expect(document.body).toHaveFocus();
userEvent.tab({ shift: true });
expect(screen.getByText('First option')).toHaveFocus();
});
What you did:
Ran the test.
What happened:
The test failed.
expect(element).toHaveFocus()
Expected
<body><div><ul role="listbox"><li role="option" tabindex="0">First option</li><li role="option" tabindex="-1">Second option</li></ul></div></body>
Received:
<li role="option" tabindex="0">First option</li>
76 |
77 | userEvent.tab();
> 78 | expect(document.body).toHaveFocus();
| ^
79 |
80 | userEvent.tab({ shift: true });
81 | expect(screen.getByText('First option')).toHaveFocus();
Reproduction repository:
Problem description:
It looks like the tab
method does not consider the body as a tabable element. That is actually not true – at least from doing a quick experiment in Chrome.
The following screenshot is the experiement.
- Render a button
- Look at active element (body)
- Press tab
- Look at active element (button)
- Press tab
- Look at active element (body)
Suggested solution:
Assuming the focus trap is on the document, always set the body as the first tabable element.
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
ARIA: document role - Accessibility - MDN Web Docs - Mozilla
The document role is for focusable content within complex composite widgets or applications for which assistive technologies can switch ...
Read more >Focusable Elements - Browser Compatibility Table - ally.js
Element Expected Chrome Chrome Microsoft Edge Microsoft Edge Microsoft Edge
Element Expected 55.0 57.0 12.10240 13.10586 14.14393
tabbable. 0 tabbable. 0 tabbable. 0 tabbable. 0...
Read more >Getting keyboard-focusable elements | Zell Liew
If you create JavaScript widgets, one of the key parts to accessibility is managing focus. To manage focus, you need to find keyboard-focusable...
Read more >How to Determine Which Element Has Focus in JavaScript
Form controls like input, select, textarea, and button are all focusable if they are not disabled, as are objects. Other elements, such as ......
Read more >First focusable element is link to main content - Rules
the element is keyboard actionable; and · the element is included in the accessibility tree; and · the element has a semantic role...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@nickmccurdy I appreciate the analysis and clarification. I think you’re 100% right.
My latest train of thought: I think it is sensible to simulate a single active element outside the page tab sequence.
When a developer is testing a UI element, it seems reasonable to test the case of tabbing past the UI element. If the UI element was a single page application, it seems reasonable to tab out of the application.
As it now stands, the jsdom implementation sets the active element to be document.body on first render (given a React test). This allows a developer to test a UI element from lack of focus to focus without any additional testing overhead. It seems reasonable to provide the reverse: focus to lack of focus without any additional testing overhead.
Suggested theoretical solution:
document.activeElement === document.body
), pressing tab will focus the first thing in the page tab sequence.document.activeElement === document.body
), pressing shift+tab will focus the last thing in the page tab sequence.document.activeElement.blur()
document.activeElement.blur()
Outside of scope:
toHaveFocus
seems to be a problem but I think it might be an additional issue instead of the same issue.Whaddya’ll think?
🎉 This issue has been resolved in version 12.0.3 🎉
The release is available on:
npm package (@latest dist-tag)
Your semantic-release bot 📦🚀