diff --git a/src/event/behavior/keydown.ts b/src/event/behavior/keydown.ts index e0d5b9be..6008399c 100644 --- a/src/event/behavior/keydown.ts +++ b/src/event/behavior/keydown.ts @@ -101,7 +101,7 @@ const keydownBehavior: { Tab: (event, target, instance) => { return () => { const dest = getTabDestination( - target, + document.activeElement ?? target, instance.system.keyboard.modifiers.Shift, ) focusElement(dest) diff --git a/tests/event/behavior/keydown.ts b/tests/event/behavior/keydown.ts index da6f10dc..7f1d39a3 100644 --- a/tests/event/behavior/keydown.ts +++ b/tests/event/behavior/keydown.ts @@ -303,6 +303,51 @@ cases( }, ) +cases( + 'tab from a target moved during the keyboard event', + ({focus, shiftKey = false, expectedFocus, expectedSelection}) => { + const {xpathNode} = render( + ``, + { + focus, + }, + ) + + const instance = setupInstance() + instance.system.keyboard.modifiers.Shift = shiftKey + + document.activeElement?.addEventListener('keydown', (e) => { + xpathNode('button[1]').focus() + }) + instance.dispatchUIEvent(document.activeElement as Element, 'keydown', { + key: 'Tab', + }) + expect(xpathNode(expectedFocus)).toHaveFocus() + if (expectedSelection) { + expect(getUISelection(xpathNode(expectedFocus))).toEqual( + expect.objectContaining(expectedSelection), + ) + } + }, + { + 'tab to input2': { + focus: '//body', + expectedFocus: 'input[2]', + expectedSelection: {startOffset: 0, endOffset: 4}, + }, + 'tab to number input': { + focus: 'input[1]', + expectedFocus: 'input[2]', + expectedSelection: {startOffset: 0, endOffset: 4}, + }, + 'tab backward to input1': { + focus: 'input[2]', + shiftKey: true, + expectedFocus: 'input[1]', + }, + }, +) + cases( 'walk through radio group per arrow keys', ({focus, key, expectedTarget}) => {