Some Hamburger Helper for Turbo and Bulma

Cheesy!


If you use Bulma CSS, Turbo, and Stimulus in your web project, you may have noticed that the hamburger menu in the navbar doesn't work, and that you need to supply your own Javascript to make it work. While this is explained in the docs -- Bulma doesn't include any Javascript, after all -- the plain JS example provided doesn't work on websites using Turbo.

This occurs because, on a new page load, Turbo replaces the click handler's DOM element with new elements, even if that aspect of the page hasn't changed, without calling DOMContentLoaded (or any other startup event). Meaning, we cannot use DOMContentLoaded to set our click handlers!

So we need something else: instead of DOMContentLoaded we can use Stimulus to add a little "hamburger helper" to the project and get that menu working!

First, we want to create a new Stimulus controller, which we will call navbar_controller.js. In it, we will create one action, toggleMenu(), which will handle the click event and control the hamburger menu by toggling the is-active class on the hamburger HTML elements. In that file, add the following code:

import {Controller} from '@hotwired/stimulus';

// Navbar toggle
// Adapted from https://bulma.io/documentation/components/navbar/#navbar-menu

export default class extends Controller {

    toggleMenu() {

        // Get all "navbar-burger" elements
        const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);

        // Get the target from the "data-target" attribute
        const target = this.element.dataset.target;
        const $target = document.getElementById(target);

        // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
        this.element.classList.toggle('is-active');
        $target.classList.toggle('is-active');

    }

}

Then, in your navbar HTML code, find the <a role="button" class="navbar-burger"> tag that comprises the hamburger button and add the following data attributes:
  • data-controller: set this to the name of your Navbar controller: "navbar"
  • data-action: use this to bind the click event to toggleMenu(): "click->navbar#toggleMenu"
  • data-target: set this to the id of your navbar <div> element, which should have a class of navbar-menu. On this site, the element's id is "ze-navbar", so that would be the value for this data attribute.

Once you've done that, your .navbar-burger HTML element should look something like this:

<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-controller="navbar" data-action="click->navbar#toggleMenu" data-target="[your navbar id here]">
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
</a>

And that should be it! Reload the page and everything should work nicely.

I know this seems extremely basic, but if you are like me and still a bit overwhelmed by all the quirks and eccentricities of building a web app in Turbo, you might be thankful to have it all spelled out for you. I certainly would have liked that!

sui generis.

Lyjia's Blog

See posts by category: