@terrahq/collapsify.js
Javascript module for accordion/collapse/tabs written in Vanilla js.
> examples
Usage
Install
npm install @terrahq/collapsify
Import
import Collapsify from "@terrahq/collapsify";
Initialize
new Collapsify(options);
Markup
Minimum markup
<button type="button" data-collapsify-control="uniqID">Show/Hide Content</button>
<div data-collapsify-content="uniqID">Toggle Content</div>
With aria-*
attribute for accessibility
<button type="button" data-collapsify-control="uniqID" aria-expanded="false" aria-controls="contentID">Show/Hide Content</button>
<div id="contentID" data-collapsify-content="uniqID" aria-hidden="true">Toggle Content</div>
Options
nameSpace | string | "collapsify" | Set namespace for "toggleButtonAttr", "toggleContentAttr" & "toggleSelectOptionsAttr" |
toggleButtonAttr | string | "data-collapsify-control" | data attribute for Button Element |
toggleContentAttr | string | "data-collapsify-content" | data attribute for Content |
dropdownElement | HTMLSelectElement | - | HTML dropdown element for tablets/mobiles |
isTab | boolean | false | The package being used for tabs |
activeClass | string | "is-active" | Add class on opened Element |
isAnimation | boolean | true | animation Slide |
closeOthers | boolean | true | Close others Content |
animationSpeed | number | 400 | css transition duration(ms) |
cssEasing | string | "ease-in-out" | css transition easing (only isAnimation:true) |
onSlideStart | (isOpen:boolean,contentID:string)=> void | Promise | () => void | Callback on Open/Close Animation Start. Supports async/await @param {Boolean} isOpen @param {String} contentID * Don't ID Attribute |
onSlideEnd | (isOpen:boolean,contentID:string)=> void | Promise | () => void | Callback on Open/Close Animation End. Supports async/await @param {Boolean} isOpen @param {String} contentID * Don't ID Attribute |
onComplete | () => void | Promise | () => void | Callback triggered after Collapsify finishes initialization. Supports async/await |
Methods
Open/Close Content
collapsify.open(contentID, [isRunCallback, isAnimation]);
collapsify.close(contentID, [isRunCallback, isAnimation]);
Samples
JS
const myAccrodion = new Collapsify();
const myAccrodionCustom = new Collapsify({
nameSpace: "collapsify",
activeClass: "is-active",
isAnimation: true,
closeOthers: true,
animationSpeed: 400,
cssEasing: "ease",
onSlideStart: (isOpen, contentID) => {
console.log(isOpen);
const buttonEl = document.querySelectorAll(`[data-collapsify-control='${contentID}']`);
console.log(buttonEl);
},
onSlideEnd: (isOpen, contentID) => {
console.log(isOpen);
const contentEl = document.querySelector(`[data-collapsify-content='${contentID}']`);
console.log(contentEl);
},
onComplete: () => {
console.log('myAccrodionCustom is loaded!');
}
});
myAccrodion.open("content01");
myAccrodion.close("content01");
Async/Await Support
Collapsify now supports async/await in all callback functions. The library will wait for async operations to complete before proceeding with animations.
const asyncCollapsify = new Collapsify({
nameSpace: "async-example",
onSlideStart: async (isOpen, contentID) => {
console.log('Starting animation...');
try {
await fetch('/api/track-interaction', {
method: 'POST',
body: JSON.stringify({
action: isOpen ? 'open' : 'close',
contentID: contentID
})
});
console.log('Analytics tracked successfully');
} catch (error) {
console.error('Failed to track analytics:', error);
}
},
onSlideEnd: async (isOpen, contentID) => {
console.log('Animation completed');
if (isOpen) {
try {
const response = await fetch(`/api/content/${contentID}`);
const data = await response.json();
const contentEl = document.querySelector(`[data-async-example-content='${contentID}']`);
if (contentEl) {
contentEl.innerHTML = data.html;
}
} catch (error) {
console.error('Failed to load dynamic content:', error);
}
}
},
onComplete: async () => {
console.log('Initializing...');
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Collapsify fully initialized with async support!');
}
});
Key Features:
- All callbacks (
onSlideStart
, onSlideEnd
, onComplete
) support async functions
- The library waits for async operations to complete before continuing
- Perfect for API calls, dynamic content loading, analytics tracking, etc.
- Maintains backward compatibility with synchronous callbacks
HTML Examples
Basic Collapse/Toggle
<button type="button" data-collapsify-control="content01" aria-expanded="false" aria-controls="basicContent01">
Show/Hide Content
</button>
<div id="basicContent01" data-collapsify-content="content01" aria-hidden="true">
<p>This content can be toggled open and closed.</p>
</div>
Accordion
<div class="accordion">
<button type="button" class="is-active" data-collapsify-control="accordion01" aria-expanded="true" aria-controls="accordionContent01">
Section 1 Title
</button>
<div id="accordionContent01" class="is-active" data-collapsify-content="accordion01" aria-hidden="false">
<p>Content for section 1. This section is open by default.</p>
</div>
<button type="button" data-collapsify-control="accordion02" aria-expanded="false" aria-controls="accordionContent02">
Section 2 Title
</button>
<div id="accordionContent02" data-collapsify-content="accordion02" aria-hidden="true">
<p>Content for section 2.</p>
</div>
<button type="button" data-collapsify-control="accordion03" aria-expanded="false" aria-controls="accordionContent03">
Section 3 Title
</button>
<div id="accordionContent03" data-collapsify-content="accordion03" aria-hidden="true">
<p>Content for section 3.</p>
</div>
</div>
Tabs
<div class="tabs">
<div class="tab-nav">
<button type="button" class="is-active" data-tab-control="tab01" aria-expanded="true">
Tab 1
</button>
<button type="button" data-tab-control="tab02" aria-expanded="false">
Tab 2
</button>
<button type="button" data-tab-control="tab03" aria-expanded="false">
Tab 3
</button>
<select class="tab-dropdown">
<option value="" disabled selected>Select Tab</option>
<option data-tab-dropdown-item="tab01" value="">Tab 1</option>
<option data-tab-dropdown-item="tab02" value="">Tab 2</option>
<option data-tab-dropdown-item="tab03" value="">Tab 3</option>
</select>
</div>
<div class="tab-content">
<div class="is-active" data-tab-content="tab01" aria-hidden="false">
<p>Content for Tab 1. This tab is active by default.</p>
</div>
<div data-tab-content="tab02" aria-hidden="true">
<p>Content for Tab 2.</p>
</div>
<div data-tab-content="tab03" aria-hidden="true">
<p>Content for Tab 3.</p>
</div>
</div>
</div>
Nested Accordion
<div class="nested-accordion">
<button type="button" data-collapsify-control="parentContent" aria-expanded="false" aria-controls="parentContentDiv">
Parent Section
</button>
<div id="parentContentDiv" data-collapsify-content="parentContent" aria-hidden="true">
<p>Parent content...</p>
<button type="button" data-collapsify-control="childContent" aria-expanded="false" aria-controls="childContentDiv">
Child Section
</button>
<div id="childContentDiv" data-collapsify-content="childContent" aria-hidden="true">
<p>Child content nested inside parent.</p>
</div>
</div>
</div>
JavaScript Initialization for Each Case
const collapse = new Collapsify();
const accordion = new Collapsify({
closeOthers: true
});
const tabs = new Collapsify({
nameSpace: "tab",
isTab: true,
closeOthers: true,
dropdownElement: document.querySelector('.tab-dropdown')
});
const parentAccordion = new Collapsify({
nameSpace: "collapsify"
});
JS
const tab = new Collapsify({
nameSpace: "tab",
closeOthers: true,
isTab: true,
dropdownElement: document.querySelector(".js--select-item-a"),
});
HTML
<div class="c--tabs-a">
<div class="c--tabs-a__hd">
<ul class="c--tabs-a__hd__list">
<li class="c--tabs-a__hd__list__list-item">
<button
class="c--tabs-a__hd__list__list-item__link c--tabs-a__hd__list__list-item__link--is-active js--select-tab"
type="button"
data-tab-control="tabContent-01"
aria-expanded="false"
>
Tab 01
</button>
</li>
<li class="c--tabs-a__hd__list__list-item">
<button class="c--tabs-a__hd__list__list-item__link js--select-tab" type="button" data-tab-control="tabContent-02" aria-expanded="false">Tab 02</button>
</li>
<li class="c--tabs-a__hd__list__list-item">
<button class="c--tabs-a__hd__list__list-item__link js--select-tab" type="button" data-tab-control="tabContent-03" aria-expanded="false">Tab 03</button>
</li>
</ul>
<div class="c--tabs-a__hd__selector">
<select aria-label="tab selector" class="c--tabs-a__hd__selector__item js--select-item-a">
<option value="" disabled="" selected="">Select</option>
<option data-tab-dropdown-item="tabContent-01" value="">option 01</option>
<option data-tab-dropdown-item="tabContent-02" value="">option 02</option>
<option data-tab-dropdown-item="tabContent-03" value="">option 03</option>
</select>
</div>
</div>
<div class="c--tabs-a__bd c--tabs-a__bd--is-active" data-tab-content="tabContent-01" aria-hidden="true">
<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="tabContent-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="tabContent-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>
License