Skip to content

Collapsify

In a Collapsify, we’ll build our HTML to work with the library. It does use several of the HTML attributes to function, so we’ll be careful to implement them correctly.

First thing to note is that we’ll always have the js--collapsify class on a wrapper div. It must never be inside the collapsible sections or tabs, or we would be creating many more instances that are necessary.

To make our library function we essentially need two attributes, one in the control and one in the div, that associate one with the other. These will be structured as data-[nameSpace]-control and data-[nameSpace]-content, respectively. It is very important that both those nameSpaces and the values of the attributes are the exact same.

collapsify

<div class="f--container">
<div class="f--row">
<div class="f--col-6 js--collapsify">
<button
class="c--btn-a"
type="button"
data-collapsify-control="content01"
aria-expanded="false"
aria-controls="basicContent01"
>
Show hide Button
</button>
<div id="basicContent01" data-collapsify-content="content01" aria-hidden="true">
<p>
This content can be toggled open and closed. Lorem ipsum dolor sit amet consectetur adipisicing
elit. Atque dolore, aperiam consequatur error veniam, aliquam quod quisquam minima magni, adipisci
rem et inventore mollitia asperiores eos doloribus quia dolor numquam!
</p>
</div>
</div>
</div>
</div>

Here our data-collapsify-control and our data-collapsify-content must be the same, as we stated above, so the control is associated with the content div.

collapsify

<div class="f--container">
<div class="f--row">
<div class="f--col-12">
<div class="c--accordion-a js--collapsify-accordion">
<button
class="c--btn-a c--btn-a--is-active"
type="button"
data-accordion-control="simpleContent-01"
aria-expanded="true"
aria-controls="accordionContent-01"
>
Content 01
</button>
<div id="accordionContent-01" data-accordion-content="simpleContent-01" aria-hidden="true">
<p class="u--mb-2 u--mt-2">
First content : Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fugit repellat optio
ab fugiat pariatur eius dolores omnis ullam nostrum ad vitae praesentium ex veniam veritatis
consequatur, quidem consectetur nemo? Voluptatibus.
</p>
</div>
<button
class="c--btn-a"
type="button"
data-accordion-control="simpleContent-02"
aria-expanded="true"
aria-controls="accordionContent-02"
>
Content 02
</button>
<div id="accordionContent-02" data-accordion-content="simpleContent-02" aria-hidden="false">
<p class="u--mb-2 u--mt-2">
Second content : Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fugit repellat optio
ab fugiat pariatur eius dolores omnis ullam nostrum ad vitae praesentium ex veniam veritatis
consequatur, quidem consectetur nemo? Voluptatibus.
</p>
</div>
<button
class="c--btn-a"
type="button"
data-accordion-control="simpleContent-03"
aria-expanded="false"
aria-controls="accordionContent-03"
>
Content 03
</button>
<div id="accordionContent-03" data-accordion-content="simpleContent-03" aria-hidden="true">
<p class="u--mb-2 u--mt-2">
Third content : Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fugit repellat optio
ab fugiat pariatur eius dolores omnis ullam nostrum ad vitae praesentium ex veniam veritatis
consequatur, quidem consectetur nemo? Voluptatibus.
</p>
</div>
</div>
</div>
</div>
</div>

This one seems more complicated because it’s longer, but at its core it’s the same thing.

Each button has a data-accordion-control that pairs with the data-accordion-content of the div associated to it, and that’s enough for it to function.

collapsify

<div class="f--container">
<div class="f--row">
<div class="f--col-12">
<div class="c--tabs-a js--collapsify-tab">
<div class="c--tabs-a__hd">
<ul class="c--tabs-a__hd__list-group">
<li class="c--tabs-a__hd__list-group__list-item">
<button
class="c--tabs-a__hd__list-group__list-item__link c--btn-a c--tabs-a__hd__list__list-item__link--is-active"
type="button"
data-tab-control="tab-01"
aria-expanded="true"
>
Tab 01
</button>
</li>
<li class="c--tabs-a__hd__list-group__list-item">
<button
class="c--tabs-a__hd__list-group__list-item__link c--btn-a"
type="button"
data-tab-control="tab-02"
aria-expanded="false"
>
Tab 02
</button>
</li>
<li class="c--tabs-a__hd__list-group__list-item">
<button
class="c--tabs-a__hd__list-group__list-item__link c--btn-a"
type="button"
data-tab-control="tab-03"
aria-expanded="false"
>
Tab 03
</button>
</li>
</ul>
<div class="c--tabs-a__hd__wrapper">
<select aria-label="tab selector" class="c--tabs-a__hd__wrapper__item">
<option value="" disabled="" selected="">
Select
</option>
<option data-tab-dropdown-item="tab-01" value="">
option 01
</option>
<option data-tab-dropdown-item="tab-02" value="">
option 02
</option>
<option data-tab-dropdown-item="tab-03" value="">
option 03
</option>
</select>
</div>
</div>
<div class="c--tabs-a__bd c--tabs-a__bd--is-active" data-tab-content="tab-01" aria-hidden="false">
<p>
Content First: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores nostrum amet
excepturi eum. Quo labore, est inventore incidunt debitis voluptatum qui itaque iste quam,
asperiores aliquid illum optio atque quidem.
</p>
</div>
<div class="c--tabs-a__bd" data-tab-content="tab-02" aria-hidden="true">
<p>
Content Second: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores nostrum amet
excepturi eum. Quo labore, est inventore incidunt debitis voluptatum qui itaque iste quam,
asperiores aliquid illum optio atque quidem.
</p>
...
</div>
<div class="c--tabs-a__bd" data-tab-content="tab-03" aria-hidden="true">
<p>
Content Third: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolores nostrum amet
excepturi eum. Quo labore, est inventore incidunt debitis voluptatum qui itaque iste quam,
asperiores aliquid illum optio atque quidem.
</p>
</div>
</div>
</div>
</div>
</div>

Here we have a couple different things:

First, we have a tab system instead of an accordion system. They’re essentially very similar, though, but the accordion can be configured to have more than one option open at a time, while tabs are always mutually exclusive.

Same as before, all tab controls are marked with data-tab-control and related to each of their content divs with data-tab-content.

Aside from this, here we also have a dropdown that can help us change tabs.

To link each option to a content div, we use the data-tab-dropdown-item attribute in the option element, and its value will link it to each data-tab-content div.

Remember the nameSpaces? It is also critical to define the nameSpace in the library configuration in the handler for it to function. If we leave it blank, the default nameSpace is collapsify

This would be an example handler with custom configurations for each type of implementation:

constructor(payload) {
super(payload);
// Generic
this.callbacks = {
onComplete: () => {
// Update scroll triggers after collapsify is initialized
updateScrollTriggers({ Manager: this.Manager });
},
onSlideEnd: (isOpen, contentID) => {
// Update scroll triggers after collapsify slide ends
updateScrollTriggers({ Manager: this.Manager });
},
};
this.configSimple = ({ element }) => ({
...this.callbacks,
});
this.configAccordion = ({ element }) => ({
element,
closeOthers: true,
nameSpace: "accordion",
...this.callbacks,
});
this.configTabs = ({ element }) => ({
element,
isTab: true,
nameSpace: "tab",
dropdownElement: element.querySelector(".c--tabs-a__hd__wrapper__item"),
...this.callbacks
});
this.init();
this.events();
}

Our constructor holds our configurations.

In this case, we want a common set of callbacks for all of them, so we can define them once and reuse them across the config functions. They are in charge of updating our scroll triggers for our animations to adapt to the height of the open content elements.

Our first one only needs those callbacks, no special configuration is needed here. Remember this one had data-collapsify-control and data-collapsify-content as attributes, so it’s using the default namespace.

For the accordion one, we define our behavior (closing other elements when opening a new one) and we assign it a new nameSpace.

Lastly, the tabs contains the property that makes it effectively a set of tabs instead of a regular accordion and adds the dropdown element. Notice how we do element.querySelector and not document.querySelector. That’s because our element will be updated with the rest of the DOM when we change pages, but if we use document here we will be calling the version of the DOM that existed when the page first loaded, so it wouldn’t find the element we want on transition.

Once we have all our configurations, we only need to get our DOM in order:

get updateTheDOM() {
return {
collapsifyElement: document.querySelectorAll(`.js--collapsify`),
collapsifyAccordion: document.querySelectorAll(`.js--collapsify-accordion`),
collapsifyTab: document.querySelectorAll(`.js--collapsify-tab`),
};
}

And instantiate our elements in our events:

this.emitter.on("MitterContentReplaced", async () => {
this.DOM = this.updateTheDOM;
await super.assignInstances({
elementGroups: [
{
elements: this.DOM.collapsifyElement,
config: this.configSimple,
boostify: { distance: 30 },
},
{
elements: this.DOM.collapsifyAccordion,
config: this.configAccordion,
boostify: { distance: 30 },
},
{
elements: this.DOM.collapsifyTab,
config: this.configTabs,
boostify: { distance: 30 },
},
],
});
});

Each with its own configuration.

Lastly, we handle our destroys:

this.emitter.on("MitterWillReplaceContent", () => {
if (this.DOM.collapsifyElement.length) {
super.destroyInstances();
}
});

And that’s it!

Knowledge Check

Test your understanding of this section

Loading questions...