Dropdown with initial "show" class and data-bs-auto-close="outside" doesn't close
Prerequisites
- [x] I have searched for duplicate or closed issues
- [x] I have validated any HTML to avoid common problems
- [x] I have read the contributing guidelines
Describe the issue
I need to render a Bootstrap Dropdown element opened by default with the data-bs-auto-close="outside" attribute. For this, I use the "show" classes for the "dropdown-toggle" and "dropdown-menu" elements.
It renders as opened, but the auto-close feature doesn't work - when I click outside of the dropdown menu, it stays visible on the wepage.
Reduced test cases
Here is a Codepen repoducing this bug: https://codepen.io/MurzNN/pen/ogNVXMY
And the code:
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
Clickable outside 1
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
</ul>
</div>
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle show" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
Clickable outside 2
</button>
<ul class="dropdown-menu show">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
</ul>
</div>
The problem is with the "Clickable outside 2" button.
P.S. The Positioning of the dropdown menu is wrong too, but this is another bug https://github.com/twbs/bootstrap/issues/41148
What operating system(s) are you seeing the problem on?
Windows, Linux
What browser(s) are you seeing the problem on?
Chrome
What version of Bootstrap are you using?
v5.3.4
Hi. Bootstrap simply cannot initialize the element in advance, and even if it could, it would cause the element to flash, since the browser will render it before js starts manipulating it.
That is, bootstrap has a loader that collects all such elements by attributes and initializes them, but in this case this will not eliminate css flashing, since CSS will be processed first.
At least it can be solved like this:
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" id="custom" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
Clickable outside 2
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
</ul>
</div>
Via js
const element = document.getElementById('custom')
element.click()
or
import { Dropdown } from './index.esm.js'
new Dropdown(document.getElementById('custom')).show()
This will have the expected behavior
Thank you for such a detailed explanation! Yes, I already use a workaround with element.click() for this issue.
But, as Bootstrap already uses JS for Dropdowns, maybe we can still handle this automatically by simulating the clicks on dropdowns that are open by default? Somewhere here: https://github.com/twbs/bootstrap/blob/25aa8cc0b32f0d1a54be575347e6d84b70b1acd7/js/src/dropdown.js#L103
Unlikely, since bootstrap loads the elements at the very end of its module:
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
Dropdown.getOrCreateInstance(this).toggle()
})
You can try to change the behavior of a container that needs a pre-opened menu (d-inline-block on btn-group):
<div class="btn-group d-inline-block">
<button class="btn btn-secondary dropdown-toggle show" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Clickable outside 2
</button>
<ul class="dropdown-menu show">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
</ul>
</div>
If this does not break the layout of the internal elements, and in the case of standard use it should not, then you can do without a click.