diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 96094a3e6577..7623e790af3e 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -207,6 +207,10 @@ class Dropdown extends BaseComponent {
this._element.setAttribute('aria-expanded', 'false')
Manipulator.removeDataAttribute(this._menu, 'popper')
EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
+
+ if (this._menu && this._menu.contains(document.activeElement)) {
+ this._element.focus()
+ }
}
_getConfig(config) {
diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js
index 63ae4bd102bc..225071760377 100644
--- a/js/tests/unit/dropdown.spec.js
+++ b/js/tests/unit/dropdown.spec.js
@@ -2097,6 +2097,100 @@ describe('Dropdown', () => {
})
})
+ it('should focus the dropdown trigger when an item is selected (and the dropdown is hidden)', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '
',
+ ' ',
+ ' ',
+ '
'
+ ].join('')
+
+ const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const item = fixtureEl.querySelector('.dropdown-item')
+
+ toggle.addEventListener('shown.bs.dropdown', () => {
+ item.focus()
+ item.click()
+ })
+
+ toggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => {
+ expect(document.activeElement).toEqual(toggle)
+ resolve()
+ }))
+
+ toggle.click()
+ })
+ })
+
+ it('should not focus the dropdown trigger when an item is selected and something else is focused in the hidden event', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '',
+ '',
+ ' ',
+ ' ',
+ '
'
+ ].join('')
+
+ const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const item = fixtureEl.querySelector('.dropdown-item')
+ const focusTarget = fixtureEl.querySelector('.focus-target')
+
+ toggle.addEventListener('shown.bs.dropdown', () => {
+ item.focus()
+ item.click()
+ })
+
+ toggle.addEventListener('hidden.bs.dropdown', () => {
+ focusTarget.focus()
+ setTimeout(() => {
+ expect(document.activeElement).toEqual(focusTarget)
+ expect(document.activeElement).not.toEqual(toggle)
+ resolve()
+ })
+ })
+
+ toggle.click()
+ })
+ })
+
+ it('should not throw an error when the dropdown was disposed in the hidden event', () => {
+ return new Promise(resolve => {
+ fixtureEl.innerHTML = [
+ '',
+ ' ',
+ ' ',
+ '
'
+ ].join('')
+
+ const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
+ const item = fixtureEl.querySelector('.dropdown-item')
+
+ toggle.addEventListener('shown.bs.dropdown', () => {
+ item.click()
+ })
+
+ toggle.addEventListener('hidden.bs.dropdown', () => {
+ const dropdown = Dropdown.getInstance(toggle)
+ dropdown.dispose()
+
+ setTimeout(() => {
+ expect(dropdown._menu).toBeNull()
+ resolve()
+ })
+ })
+
+ toggle.click()
+ })
+ })
+
it('should close dropdown (only) by clicking inside the dropdown menu when it has data-attribute `data-bs-auto-close="inside"`', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [