Skip to content

Instantly share code, notes, and snippets.

@stewartknapman
Created June 11, 2019 18:48
Show Gist options
  • Save stewartknapman/ff9f52b97fab157285b2aa94903a7e9b to your computer and use it in GitHub Desktop.
Save stewartknapman/ff9f52b97fab157285b2aa94903a7e9b to your computer and use it in GitHub Desktop.
(function () {
if (!document.querySelector && !window.addEventListener && !("classList" in document.createElement("p"))) return;
var ready = function (callback, ctx) {
if (typeof callback !== 'function') return;
if (document.readyState !== "loading") {
callback.apply(ctx);
} else {
document.addEventListener("DOMContentLoaded", function () {
callback.apply(ctx);
});
}
};
var each = function (arr, callback, ctx) {
var r;
for (var i = 0; i < arr.length; i++) {
ctx = ctx || arr[i];
r = callback.apply(ctx, [arr[i], i]);
if (r == false) break;
}
};
var debounce = function (callback, wait, ctx) {
var timeout, timestamp, args;
wait = wait || 100;
var later = function() {
var last = new Date().getTime() - timestamp;
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
callback.apply(ctx, args);
}
};
return function () {
ctx = ctx || this;
args = arguments;
timestamp = new Date().getTime();
if (!timeout) timeout = setTimeout(later, wait);
};
};
/* Accordian Main */
var Accordian = function (ele, selectors) {
this.classes = {
open: 'accordion__section--open'
};
this.selectors = selectors;
this.ele = ele;
this.sections = this._getSections();
this._setContentHeights();
this._addEventListeners();
};
Accordian.prototype.toggleSection = function (target) {
var targetEle = this.ele.querySelector(target);
var currentSection = targetEle.closest(this.selectors.sections);
var isclosed = true;
if (currentSection.classList.contains(this.classes.open)) {
isclosed = false;
}
this.closeSections();
if (isclosed) {
var content = currentSection.querySelector(this.selectors.content);
currentSection.classList.add(this.classes.open);
content.style.height = content.getAttribute('data-height');
}
};
Accordian.prototype.closeSections = function () {
each(this.sections, function (section) {
var content = section.querySelector(this.selectors.content);
content.style.height = '0';
section.classList.remove(this.classes.open);
}, this);
};
Accordian.prototype._addEventListeners = function () {
var _this = this;
this.actions = this.ele.querySelectorAll(this.selectors.actions);
each(this.actions, function (action) {
action.addEventListener('click', function (e) {
var target = e.currentTarget.getAttribute('href');
e.preventDefault();
_this.toggleSection(target);
});
});
window.addEventListener('resize', debounce(function () {
_this._setContentHeights();
}));
};
Accordian.prototype._getSections = function () {
var sectionClassName = this.selectors.sections.replace('.','');
if (this.ele.classList.contains(sectionClassName)) {
return [this.ele];
} else {
return this.ele.querySelectorAll(this.selectors.sections);
}
};
Accordian.prototype._setContentHeights = function () {
var contents = this.ele.querySelectorAll(this.selectors.content);
each(contents, function (content) {
var transition = window.getComputedStyle(content).transition;
var currentHeightStyle = window.getComputedStyle(content).height;
content.style.transition = 'none';
content.style.height = 'auto';
content.setAttribute('data-height', content.offsetHeight+'px');
content.style.height = currentHeightStyle;
content.style.transition = transition;
});
};
// Plural
var Accordians = function () {
this.selectors = {
ele: '[data-accordion]',
sections: '.accordion__section',
content: '.accordion__content',
actions: 'a'
}
this.init();
};
Accordians.prototype.init = function () {
this.eles = document.querySelectorAll(this.selectors.ele);
if (!this.eles.length) return;
each(this.eles, function (ele) {
new Accordian(ele, this.selectors);
}, this);
};
// Run everything
ready(function () {
new Accordians();
});
})();
<div class="accordion" data-accordion>
<!-- Start section -->
<div class="accordion__section accordion__section--features accordion__section--open">
<div class="accordion__header">
<h3>
<a href="#section1">
Section 1 title
{% include 'icon-plus' %}
{% include 'icon-minus' %}
</a>
</h3>
</div>
<div class="accordion__content" id="section1">
<ul class="rte">
Section 1 content
</ul>
</div>
</div>
<!-- End section -->
</div>
.accordion {
margin-bottom: $grid-gutter;
border-bottom: $color-border solid 1px;
ul {
padding-left: 1.25em;
}
}
.accordion__header {
padding-top: 1.5em;
border-top: $color-border solid 1px;
a {
display: block;
}
.icon {
float: right;
.no-js & {
display: none !important;
}
}
.icon-plus {
display: block;
.accordion__section--open & {
display: none;
}
}
.icon-minus {
display: none;
.accordion__section--open & {
display: block;
}
}
}
.accordion__content {
overflow: hidden;
.js & {
height: 0;
transition: .2s height ease-in-out;
}
.no-js &,
.accordion__section--open & {
height: auto;
margin-bottom: 1.5em;
}
}
@stewartknapman
Copy link
Author

This was based on the Debut theme which has icons in the snippets folder. You can aways replace the icon includes with your own icons or svg

@edwardboyce
Copy link

I have the opposite problem in that all the tabs are open when loaded, then once tab is clicked they resume correct behaviour. I'm really struggling to see why it's doing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment