@mdo

Toggling classes with JavaScript

March 2, 2022

During my recovery I’ve made it a point to double down on improving my rather limited JavaScript skills. Courses have been helpful, but it seems that no matter the course, I do my best learning by making things myself. So I’ve been tinkering around and trying to build some new projects.

My latest experiment was to build something that allows me to toggle a class on an element with a particular id.

<button type="button" data-toggle-target="#example" data-toggle-class="blue">
  Toggle
</button>

<div id="example">
  This element will have the <code>.blue</code> class toggled on it.
</div>

The gist is that I want to use a <button> to toggle any class I want on another element of my choosing, all using data attributes so that it’s infinitely flexible and functional in any context.

Nothing big, but something I knew I wanted to demo it for the Bootstrap team so we could add a potentially new component in Bootstrap. After seeing what my original demo turned into with that pull request, I realized I had set my sights too low. Instead of toggling classes with a target with only an ID, why not specify targets by classes, attribute, or any other selector? So I rebuilt it to do just that.

Here’s the final demo via CodePen.

See the Pen Toggle anything via data-attribute by Mark Otto (@emdeoh) on CodePen.

Here’s a walk through the JavaScript I wrote.

First, we find all the elements that have the data-toggle-target attribute so we can trigger our JavaScript on them.

let toggler = document.querySelectorAll("[data-toggle-target]")

Second, we add a quick check to see if there are any matching elements with that selector. This way our JavaaScript will only run if there are any elements to actually toggle.

if (toggler) {
  //
}

From there, we use a forEach loop to execute code against every matching instance of our selector from the toggler var. Within that loop, we then access the data attributes so we can use them later.

if (toggler) {
  toggler.forEach(function (element) {
    let target = element.getAttribute("data-toggle-target")
    let targets = document.querySelectorAll(target)
    let toggleClass = element.getAttribute("data-toggle-class")

    //
  }
}

Finally, we add an event listener to eacch toggling element (aka, the button) that toggles the specified class from toggleClass.

let toggler = document.querySelectorAll("[data-toggle-target]")

if (toggler) {
  toggler.forEach(function (element) {
    let target = element.getAttribute("data-toggle-target")
    let targets = document.querySelectorAll(target)
    let toggleClass = element.getAttribute("data-toggle-class")

    element.addEventListener("click", (event) => {
      targets.forEach(function (e) {
        e.classList.toggle(toggleClass)
      })
    })
  })
}

If I had to improve things further, I’d like the trigger to be customizable to click, change (for form elements), hover, and focus. I’d also consider toggling ids and other selectors on the target element. Maybe in another post and experiment.