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) {