January 23, 2021

I Built A Bulma Extension

I built a component that ties in with Bulma to expand their collapsible offerings

I use Bulma, like, a lot. I really like how quick and easy it is to get started and you can use many build tools with it. I like the amount of built-in components that come with it but I've always been disappointed about a few things that are missing - namely, a collapsible container and a carousel. They have some non-official extensions, but the offerings for those are slim and didn't really match what I was going for, so I built my own Bulma Collapsible.


How It Works

The basic function of the collapsible is that there is a title, then some content which collapses or expands when the title is clicked on. I wanted to animate that transition, so I figured out a way to do it with CSS. The markup is as follows:

  
<div class='collapsible' id='example'>
  <div class='collapsible-header' data-controls='example'>
    <h1>Title</h1>
    <i class='fa fa-chevron-down collapsible-toggle'></i>
  </div>
  <div class='collapsible-body'>
    <!--Collapsible content goes here, a <p> tag works best-->
  </div>
</div>
  

The markup reflects some necessary things that allow JavaScript to change the classes. Speaking of classes, the CSS is pretty straightforward. The "design" part of it comes from Bulma, for the most part. I just added a flex-box display to the header so that the button and title play nicely, but that wasn't 100% necessary - I could have put the button before the header tag in the markup and put display: inline-block; on both of them, but I like flex-box more.
The meat and potatoes of the CSS is the transition on the div.collapsible-body element. The initial height is set to 0 with overflow-y hidden. When the collapsible has the class of .is-active, the height rule of .collapsible-body is reset via JS, allowing the CSS transition rule to take hold and collapse or expand the body visually. Oh, it also rotates the chevron icon so it's facing the other way. Note that the CSS below does not include the stuff to make it look good, this is all purely functional.

  
.collapsible .collapsible-header .collapsible-toggle {
  transition: transform 0.3s ease;
}
.collapsible .collapsible-body {
  height: 0;
  overflow-y: hidden;
  transition: height 0.4s ease;
}
.collapsible.is-active .collapsible-toggle {
  transform: rotate(180deg);
  transition: transform 0.3s ease;
}
.collapsible.is-active .collapsible-body {
  transition: height 0.4s ease;
}
  

The final height is determined with JavaScript and set with an inline style. After running document.querySelectorAll('.collapsible-header'), an event listener gets assigned to every instance of .collapsible-header, which toggles the .is-active class on the target and header. The height of the .collapsible-content is calculated, then assigned to .collapsible-body if the .collapsible has the .is-active class. The height is set back to '0' if not.

  
var target = document.getElementById(el.dataset.controls);
target.classList.toggle('is-active');
el.classList.toggle('is-active');
var body = document.querySelector("#" + el.dataset.controls + " .collapsible-body");
var content = document.querySelector("#" + el.dataset.controls + " .collapsible-content");
var setHeight = content.getBoundingClientRect().height;
if (target.classList.contains('is-active')) {
  body.style.height = setHeight + "px";
} else {
  body.style.height = 0;
}
  

It really comes all together in the CodePen. Check that out below. See this in a real world application at my FAQ.

See the Pen Collapsible - Bulma by Nate Northway (@the_Northway) on CodePen.