javascriptbootstrap-5

Opening a bootstrap5 dropdown programmatically only works in the browser's dev console, not in vanilla JS code


I tried to open a Bootstrap5 dropdown when clicking a link in my web app. I tried dispatching events and using the bootstrap Dropdown classes, both without success. The code of both approaches works, when I run it in the developers console (Firefox & Chromium).

I stripped everything but bootstrap and wrote this micro website to make sure nothing else interferes with the code:

<html>

<head>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
  <script>
    function test() {
      document.getElementById("dropdownMenuButton1").click();
    }
  </script>
</head>

<body>
  <!-- This is the dropdown example from the official bootstrap5 docs -->
  <div class="dropdown">
    <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
    Dropdown button
  </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
      <li><a class="dropdown-item" href="#">Action</a></li>
      <li><a class="dropdown-item" href="#">Another action</a></li>
      <li><a class="dropdown-item" href="#">Something else here</a></li>
    </ul>
  </div>
  <!-- Now the button, that should trigger a click on the dropdown -->
  <button class="btn btn-primary" onclick="test()">Open Dropdown</button>
</body>

</html>

It's not working, but when I run

document.getElementById("dropdownMenuButton1").click();

in the dev console, the dropdown opens.


Solution

  • Thanks @Quentin for the hint with the autoclose options. I still don't understand why the click event works in the developers console, but not in the script on the website.

    However I managed to solve the problem with this hacky approach:

    <html>
    <head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script>
    function test(){
      const elm = document.getElementById("dropdownMenuButton1");
      //  this disables the auto closing
      elm.setAttribute("data-bs-auto-close", "false");
      //  now open the dropdown
      new bootstrap.Dropdown(elm).show();
      //  restore the original state
      elm.removeAttribute("data-bs-auto-close");
      //  recreate the dropdown to apply the original state.
      //  without the timeout it does not work (it's not opening).
      setTimeout(() => {
        new bootstrap.Dropdown(elm);
      }, 10);
    }
    </script>
    </head>
    <body>
    <!-- This is the dropdown example from the official bootstrap5 docs -->
    <div class="dropdown">
      <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
        Dropdown button
      </button>
      <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
        <li><a class="dropdown-item" href="#">Action</a></li>
        <li><a class="dropdown-item" href="#">Another action</a></li>
        <li><a class="dropdown-item" href="#">Something else here</a></li>
      </ul>
    </div>
    <!-- Now the button, that should trigger a click on the dropdown -->
    <button class="btn btn-primary" onclick="test()">Open Dropdown</button>
    </body>
    </html>

    This makes it possible to open the dropdown by clicking another element and keep the original behavior of the dropdown menu.