diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 0d55afda70..81ce288d70 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix hanging tests when using `anchor` prop ([#3357](https://github.com/tailwindlabs/headlessui/pull/3357)) - Fix `transition` and `focus` prop combination for `PopoverPanel` component ([#3361](https://github.com/tailwindlabs/headlessui/pull/3361)) - Fix outside click in nested portalled `Popover` components ([#3362](https://github.com/tailwindlabs/headlessui/pull/3362)) +- Fix restoring focus to correct element when closing `Dialog` component ([#3365](https://github.com/tailwindlabs/headlessui/pull/3365)) ## [2.1.1] - 2024-06-26 diff --git a/packages/@headlessui-react/src/utils/active-element-history.ts b/packages/@headlessui-react/src/utils/active-element-history.ts index d75dbb3997..1b66e06131 100644 --- a/packages/@headlessui-react/src/utils/active-element-history.ts +++ b/packages/@headlessui-react/src/utils/active-element-history.ts @@ -1,4 +1,5 @@ import { onDocumentReady } from './document-ready' +import { focusableSelector } from './focus-management' export let history: HTMLElement[] = [] onDocumentReady(() => { @@ -7,7 +8,21 @@ onDocumentReady(() => { if (e.target === document.body) return if (history[0] === e.target) return - history.unshift(e.target) + let focusableElement = e.target as HTMLElement + + // Figure out the closest focusable element, this is needed in a situation + // where you click on a non-focusable element inside a focusable element. + // + // E.g.: + // + // ```html + // + // ``` + focusableElement = focusableElement.closest(focusableSelector) as HTMLElement + + history.unshift(focusableElement ?? e.target) // Filter out DOM Nodes that don't exist anymore history = history.filter((x) => x != null && x.isConnected) diff --git a/packages/@headlessui-react/src/utils/focus-management.ts b/packages/@headlessui-react/src/utils/focus-management.ts index 7567d656fd..1a39a3b5c4 100644 --- a/packages/@headlessui-react/src/utils/focus-management.ts +++ b/packages/@headlessui-react/src/utils/focus-management.ts @@ -5,7 +5,7 @@ import { getOwnerDocument } from './owner' // Credit: // - https://stackoverflow.com/a/30753870 -let focusableSelector = [ +export let focusableSelector = [ '[contentEditable=true]', '[tabindex]', 'a[href]', diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index f5c040b2fc..4927170da8 100644 --- a/packages/@headlessui-vue/CHANGELOG.md +++ b/packages/@headlessui-vue/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Cancel outside click behavior on touch devices when scrolling ([#3266](https://github.com/tailwindlabs/headlessui/pull/3266)) +- Fix restoring focus to correct element when closing `Dialog` component ([#3365](https://github.com/tailwindlabs/headlessui/pull/3365)) ## [1.7.22] - 2024-05-08 diff --git a/packages/@headlessui-vue/src/utils/active-element-history.ts b/packages/@headlessui-vue/src/utils/active-element-history.ts index d75dbb3997..1b66e06131 100644 --- a/packages/@headlessui-vue/src/utils/active-element-history.ts +++ b/packages/@headlessui-vue/src/utils/active-element-history.ts @@ -1,4 +1,5 @@ import { onDocumentReady } from './document-ready' +import { focusableSelector } from './focus-management' export let history: HTMLElement[] = [] onDocumentReady(() => { @@ -7,7 +8,21 @@ onDocumentReady(() => { if (e.target === document.body) return if (history[0] === e.target) return - history.unshift(e.target) + let focusableElement = e.target as HTMLElement + + // Figure out the closest focusable element, this is needed in a situation + // where you click on a non-focusable element inside a focusable element. + // + // E.g.: + // + // ```html + // + // ``` + focusableElement = focusableElement.closest(focusableSelector) as HTMLElement + + history.unshift(focusableElement ?? e.target) // Filter out DOM Nodes that don't exist anymore history = history.filter((x) => x != null && x.isConnected) diff --git a/packages/@headlessui-vue/src/utils/focus-management.ts b/packages/@headlessui-vue/src/utils/focus-management.ts index 0b68f7dda3..7ac88984d0 100644 --- a/packages/@headlessui-vue/src/utils/focus-management.ts +++ b/packages/@headlessui-vue/src/utils/focus-management.ts @@ -4,7 +4,7 @@ import { getOwnerDocument } from './owner' // Credit: // - https://stackoverflow.com/a/30753870 -let focusableSelector = [ +export let focusableSelector = [ '[contentEditable=true]', '[tabindex]', 'a[href]',