cypress-plugin-tab
cypress-plugin-tab copied to clipboard
If a `keydown` handler changes focus, `cy.tab` will chose the wrong element
We have a focus redirect JS function for managing focus of a non-modal dialog. According to WCAG focus requirements, a non-modal dialog should be in the focus order after a triggering button:
https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-order.html
A Web page implements modeless dialogs via scripting. When the trigger button is activated, a dialog opens. The interactive elements in the dialog are inserted in the focus order immediately after the button. When the dialog is open, the focus order goes from the button to the elements of the dialog, then to the interactive element following the button. When the dialog is closed, the focus order goes from the button to the following element.
Since we "portal" our dialog, we manage focus manually. When we're on the last focusable element in a dialog, a keydown
handler will close the dialog and shift focus back to the triggering button. When the keydown
event is completed, the browser will perform the default action of advancing focus. This plugin uses the previous el
to determine the next focusable element before the keydown
event is processed. This means this plugin doesn't account for focus changes inside a keydown
which is a valid thing to do.
If instead doc.activeElement
was used to determine index
, this use-case would work.
But this breaks the documented API where focus()
is not necessary to tab.
Example, in the tests:
cy.get('a:first').tab()
This example allows you to skip focusing on the a:first
element and tab from it anyway, which is not how users really interact with a page. With this change, the test would have to be changed to:
cy.get('a:first').focus().tab()
@Bkucera What do you think? My proposal is more realistic to how browsers work, but would be a breaking change according to the documented API.