bootstrap icon indicating copy to clipboard operation
bootstrap copied to clipboard

Dropdown with initial "show" class and data-bs-auto-close="outside" doesn't close

Open MurzNN opened this issue 9 months ago • 3 comments

Prerequisites

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

MurzNN avatar Apr 04 '25 08:04 MurzNN

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

DenisLopatin avatar Aug 26 '25 21:08 DenisLopatin

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

MurzNN avatar Aug 27 '25 08:08 MurzNN

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.

DenisLopatin avatar Aug 27 '25 19:08 DenisLopatin