diff --git a/src/__tests__/click.js b/src/__tests__/click.js index 3c19daa2..8a0e784e 100644 --- a/src/__tests__/click.js +++ b/src/__tests__/click.js @@ -442,3 +442,20 @@ test('calls FocusEvents with relatedTarget', () => { element0, ) }) + +test('move focus to closest focusable element', () => { + const {element} = setup(` +
+
this is not focusable
+ +
+ `) + + document.body.focus() + userEvent.click(element.children[1]) + expect(element.children[1]).toHaveFocus() + + document.body.focus() + userEvent.click(element.children[0]) + expect(element).toHaveFocus() +}) diff --git a/src/click.js b/src/click.js index 5c40fda7..e8fe535f 100644 --- a/src/click.js +++ b/src/click.js @@ -61,14 +61,12 @@ function clickElement(element, init, {clickCount}) { element, getMouseEventOptions('mousedown', init, clickCount), ) - if ( - continueDefaultHandling && - element !== element.ownerDocument.activeElement - ) { - if (previousElement && !isFocusable(element)) { + if (continueDefaultHandling) { + const closestFocusable = findClosest(element, isFocusable) + if (previousElement && !closestFocusable) { blur(previousElement, init) - } else { - focus(element, init) + } else if (closestFocusable) { + focus(closestFocusable, init) } } } @@ -84,6 +82,16 @@ function clickElement(element, init, {clickCount}) { } } +function findClosest(el, callback) { + do { + if (callback(el)) { + return el + } + el = el.parentElement + } while (el && el !== document.body) + return undefined +} + function click(element, init, {skipHover = false, clickCount = 0} = {}) { if (!skipHover) hover(element, init) switch (element.tagName) {