17

Bulma dropdown doesn't seem to toggle on click. Below is the code snippet from the documentation:https://bulma.io/documentation/components/dropdown/

<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css" rel="stylesheet"/>


<div class="dropdown is-active">
  <div class="dropdown-trigger">
    <button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
      <span>Dropdown button</span>
      <span class="icon is-small">
        <i class="fa fa-angle-down" aria-hidden="true"></i>
      </span>
    </button>
  </div>
  <div class="dropdown-menu" id="dropdown-menu" role="menu">
    <div class="dropdown-content">
      <a href="#" class="dropdown-item">
        Dropdown item
      </a>
      <a class="dropdown-item">
        Other dropdown item
      </a>
      <a href="#" class="dropdown-item is-active">
        Active dropdown item
      </a>
      <a href="#" class="dropdown-item">
        Other dropdown item
      </a>
      <hr class="dropdown-divider">
      <a href="#" class="dropdown-item">
        With a divider
      </a>
    </div>
  </div>
</div>
Aakash Thakur
  • 3,837
  • 10
  • 33
  • 64

5 Answers5

26

You need to toggle the class is-active using JavaScript. When .dropdown has .is-active it changes the display of .dropdown-menu from none to block.

Here is a basic way to implement it.

var dropdown = document.querySelector('.dropdown');
dropdown.addEventListener('click', function(event) {
  event.stopPropagation();
  dropdown.classList.toggle('is-active');
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">


<div class="dropdown">
  <div class="dropdown-trigger">
    <button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
      <span>Dropdown button</span>
      <span class="icon is-small">
        <!--fontawesome required for the icon-->
        <i class="fa fa-angle-down" aria-hidden="true"></i>
      </span>
    </button>
  </div>
  <div class="dropdown-menu" id="dropdown-menu" role="menu">
    <div class="dropdown-content">
      <a href="#" class="dropdown-item">
        Dropdown item
      </a>
      <a class="dropdown-item">
        Other dropdown item
      </a>
      <a href="#" class="dropdown-item is-active">
        Active dropdown item
      </a>
      <a href="#" class="dropdown-item">
        Other dropdown item
      </a>
      <hr class="dropdown-divider">
      <a href="#" class="dropdown-item">
        With a divider
      </a>
    </div>
  </div>
</div>
vvmk
  • 17
  • 7
sol
  • 22,311
  • 6
  • 42
  • 59
5

Here's a full solution that has worked well for me using vanilla JS and making sure dropdowns close when you click out of them or press the Esc key.

// Get all dropdowns on the page that aren't hoverable.
const dropdowns = document.querySelectorAll('.dropdown:not(.is-hoverable)');

if (dropdowns.length > 0) {
  // For each dropdown, add event handler to open on click.
  dropdowns.forEach(function(el) {
    el.addEventListener('click', function(e) {
      e.stopPropagation();
      el.classList.toggle('is-active');
    });
  });

  // If user clicks outside dropdown, close it.
  document.addEventListener('click', function(e) {
    closeDropdowns();
  });
}

/*
 * Close dropdowns by removing `is-active` class.
 */
function closeDropdowns() {
  dropdowns.forEach(function(el) {
    el.classList.remove('is-active');
  });
}

// Close dropdowns if ESC pressed
document.addEventListener('keydown', function (event) {
  let e = event || window.event;
  if (e.key === 'Esc' || e.key === 'Escape') {
    closeDropdowns();
  }
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.css" rel="stylesheet">

<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet">

<body style="margin: 2rem">

<div class="dropdown">
  <div class="dropdown-trigger">
    <button class="button" aria-haspopup="true" aria-controls="dropdown-ui-actions">
      <span>Actions</span>
      <span class="icon is-small">
        <i class="fas fa-angle-down" aria-hidden="true"></i>
      </span>
    </button>
  </div>
  <div class="dropdown-menu" id="dropdown-ui-actions" role="menu">
    <div class="dropdown-content">
      <a href="#" class="dropdown-item">
        Option 1
      </a>
      <a href="#" class="dropdown-item">
        Option 2
      </a>
      <a href="#" class="dropdown-item">
        Option 3
      </a>
    </div>
  </div>
</div>

</body>
getup8
  • 6,949
  • 1
  • 27
  • 31
2

Add an onclick to the button:

<button class="button" onclick="this.parentNode.parentNode.classList.toggle('is-active')">
Henry
  • 2,870
  • 1
  • 25
  • 17
1

I sniffed the javascript source listener on the docs page (I don't know why they don't make this more obvious tbh) and here it is for anyone else who may benefit.

Please note below I commented out a cookies aspect which I did not have defined and was throwing an error and seemed unimportant for my purposes.

"use strict";

document.addEventListener("DOMContentLoaded", function () {
  // Search

  var setSearchToggle = function setSearchToggle() {
    var icon = document.getElementById("searchIcon");
    var search = document.getElementById("search");
    var input = document.getElementById("algoliaSearch");

    if (!icon) {
      return;
    }

    icon.addEventListener("click", function (event) {
      search.classList.toggle("bd-is-visible");

      if (search.classList.contains("bd-is-visible")) {
        algoliaSearch.focus();
      }
    });

    window.addEventListener("keydown", function (event) {
      if (event.key === "Escape") {
        return search.classList.remove("bd-is-visible");
      }
    });
  };

  setSearchToggle();

  // Navbar

  var setNavbarVisibility = function setNavbarVisibility() {
    var navbar = document.getElementById("navbar");

    if (!navbar) {
      return;
    }

    var cs = getComputedStyle(navbar);
    var paddingX = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);
    var brand = navbar.querySelector(".navbar-brand");
    var end = navbar.querySelector(".navbar-end");
    var search = navbar.querySelector(".bd-search");
    var original = document.getElementById("navbarStartOriginal");
    var clone = document.getElementById("navbarStartClone");

    var rest = navbar.clientWidth - paddingX - brand.clientWidth - end.clientWidth - search.clientWidth;

    var space = original.clientWidth;
    var all = document.querySelectorAll("#navbarStartClone > .bd-navbar-item");
    var base = document.querySelectorAll("#navbarStartClone > .bd-navbar-item-base");
    var more = document.querySelectorAll("#navbarStartOriginal > .bd-navbar-item-more");
    var dropdown = document.querySelectorAll("#navbarStartOriginal .bd-navbar-dropdown > .navbar-item");

    var count = 0;
    var totalWidth = 0;

    var showMore = function showMore() {};

    var hideMore = function hideMore() {};

    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = all[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var item = _step.value;

        totalWidth += item.offsetWidth;

        if (totalWidth > rest) {
          break;
        }

        count++;
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    var howManyMore = Math.max(0, count - base.length);

    if (howManyMore > 0) {
      for (var i = 0; i < howManyMore; i++) {
        more[i].classList.add("bd-is-visible");
        dropdown[i].classList.add("bd-is-hidden");
      }
    }

    for (var j = howManyMore; j < more.length; j++) {
      more[j].classList.remove("bd-is-visible");
    }

    for (var k = howManyMore; k < dropdown.length; k++) {
      dropdown[k].classList.remove("bd-is-hidden");
    }
  };

  setNavbarVisibility();

  // Cookies

//  var cookieBookModalName = "bulma_closed_book_modal";
//  var cookieBookModal = Cookies.getJSON(cookieBookModalName) || false;

  // Dropdowns

  var $dropdowns = getAll(".dropdown:not(.is-hoverable)");

  if ($dropdowns.length > 0) {
    $dropdowns.forEach(function ($el) {
      $el.addEventListener("click", function (event) {
        event.stopPropagation();
        $el.classList.toggle("is-active");
      });
    });

    document.addEventListener("click", function (event) {
      closeDropdowns();
    });
  }

  function closeDropdowns() {
    $dropdowns.forEach(function ($el) {
      $el.classList.remove("is-active");
    });
  }

  // Toggles

  var $burgers = getAll(".navbar-burger");

  if ($burgers.length > 0) {
    $burgers.forEach(function ($el) {
      if (!$el.dataset.target) {
        return;
      }

      $el.addEventListener("click", function () {
        var target = $el.dataset.target;
        var $target = document.getElementById(target);
        $el.classList.toggle("is-active");
        $target.classList.toggle("is-active");
      });
    });
  }

  // Modals

  var rootEl = document.documentElement;
  var $modals = getAll(".modal");
  var $modalButtons = getAll(".modal-button");
  var $modalCloses = getAll(".modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button");

  if ($modalButtons.length > 0) {
    $modalButtons.forEach(function ($el) {
      $el.addEventListener("click", function () {
        var target = $el.dataset.target;
        openModal(target);
      });
    });
  }

  if ($modalCloses.length > 0) {
    $modalCloses.forEach(function ($el) {
      $el.addEventListener("click", function () {
        closeModals();
      });
    });
  }

  function openModal(target) {
    var $target = document.getElementById(target);
    rootEl.classList.add("is-clipped");
    $target.classList.add("is-active");
  }

  function closeModals() {
    rootEl.classList.remove("is-clipped");
    $modals.forEach(function ($el) {
      $el.classList.remove("is-active");
    });
  }

  document.addEventListener("keydown", function (event) {
    var e = event || window.event;

    if (e.keyCode === 27) {
      closeModals();
      closeDropdowns();
    }
  });

  // Clipboard

  var $highlights = getAll(".highlight");
  var itemsProcessed = 0;

  if ($highlights.length > 0) {
    $highlights.forEach(function ($el) {
      var copyEl = '<button class="button bd-copy">Copy</button>';
      var expandEl = '<button class="button is-small bd-expand">Expand</button>';
      $el.insertAdjacentHTML("beforeend", copyEl);

      var $parent = $el.parentNode;

      if ($parent && $parent.classList.contains("bd-is-more")) {
        var showEl = '<button class="button is-small bd-show"><span class="icon"><i class="fas fa-code"></i></span><strong>Show code</strong></button>';
        $parent.insertAdjacentHTML("afterbegin", showEl);
      } else if ($el.firstElementChild.scrollHeight > 480 && $el.firstElementChild.clientHeight <= 480) {
        $el.insertAdjacentHTML("beforeend", expandEl);
      }

      itemsProcessed++;

      if (itemsProcessed === $highlights.length) {
        addHighlightControls();
      }
    });
  }

  function addHighlightControls() {
    var $highlightButtons = getAll(".highlight .bd-copy, .highlight .bd-expand");

    $highlightButtons.forEach(function ($el) {
      $el.addEventListener("mouseenter", function () {
        $el.parentNode.classList.add("bd-is-hovering");
        $el.parentNode.parentNode.classList.add("bd-is-hovering");
      });

      $el.addEventListener("mouseleave", function () {
        $el.parentNode.classList.remove("bd-is-hovering");
        $el.parentNode.parentNode.classList.remove("bd-is-hovering");
      });
    });

    var $highlightExpands = getAll(".bd-snippet .bd-expand");

    $highlightExpands.forEach(function ($el) {
      $el.addEventListener("click", function () {
        $el.parentNode.firstElementChild.style.maxHeight = "none";
      });
    });

    var $highlightShows = getAll(".bd-snippet .bd-show");

    $highlightShows.forEach(function ($el) {
      $el.addEventListener("click", function () {
        var text = $el.querySelector("strong").textContent;
        var newText = text === "Show code" ? "Hide code" : "Show code";
        $el.querySelector("strong").textContent = newText;
        $el.parentNode.classList.toggle("bd-is-more-clipped");
      });
    });
  }

  setTimeout(function () {
    new Clipboard(".bd-copy", {
      target: function target(trigger) {
        return trigger.previousElementSibling.firstElementChild;
      }
    });

    new Clipboard(".bd-clipboard");
  }, 100);

  // Events

  var resizeTimer = void 0;

  function handleResize() {
    window.clearTimeout(resizeTimer);

    resizeTimer = window.setTimeout(function () {
      setNavbarVisibility();
    }, 10);
  }

  window.addEventListener("resize", handleResize);

  // Utils

  function getAll(selector) {
    var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;

    return Array.prototype.slice.call(parent.querySelectorAll(selector), 0);
  }
});
jason m
  • 6,519
  • 20
  • 69
  • 122
0

correction of te answer above: I added the closeDropdowns() function, because when we click in a second menu, both menus stay opened.

// Get all dropdowns on the page that aren't hoverable.
const dropdowns = document.querySelectorAll('.dropdown:not(.is-hoverable)');

if (dropdowns.length > 0) {
  // For each dropdown, add event handler to open on click.
  dropdowns.forEach(function(el) {
    el.addEventListener('click', function(e) {
    closeDropdowns();
      e.stopPropagation();
      el.classList.toggle('is-active');
    });
  });

  // If user clicks outside dropdown, close it.
  document.addEventListener('click', function(e) {
    closeDropdowns();
  });
}

/*
 * Close dropdowns by removing `is-active` class.
 */
function closeDropdowns() {
  dropdowns.forEach(function(el) {
    el.classList.remove('is-active');
  });
}

// Close dropdowns if ESC pressed
document.addEventListener('keydown', function (event) {
  let e = event || window.event;
  if (e.key === 'Esc' || e.key === 'Escape') {
    closeDropdowns();
  }
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.css" rel="stylesheet">

<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet">

<body style="margin: 2rem">

<div class="dropdown">
  <div class="dropdown-trigger">
    <button class="button" aria-haspopup="true" aria-controls="dropdown-ui-actions">
      <span>Actions</span>
      <span class="icon is-small">
        <i class="fas fa-angle-down" aria-hidden="true"></i>
      </span>
    </button>
  </div>
  <div class="dropdown-menu" id="dropdown-ui-actions" role="menu">
    <div class="dropdown-content">
      <a href="#" class="dropdown-item">
        Option 1
      </a>
      <a href="#" class="dropdown-item">
        Option 2
      </a>
      <a href="#" class="dropdown-item">
        Option 3
      </a>
    </div>
  </div>
</div>

</body>