Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(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;
}
}
@jjp2133

This comment has been minimized.

Copy link

@jjp2133 jjp2133 commented Aug 7, 2019

Hi @stewartknapman, thank you so much for the revised accordion code. I'm still struggling a bit, as I am new to coding.

I created and linked the snippet by replacing {{product.description}} with my own {%include'myaccordionfilename'%}, and even used split heading titles from your original codes since I wanted it integrated into the heading h6. However, this time, all the heading accordions open and don't close, all while showing the content of the accordion sections.

Do you mind guiding me what I have done incorrectly? Perhaps I did not put the JS and SCSS files in the correct assets and/or snippets...

Thank you in advance!!

@stewartknapman

This comment has been minimized.

Copy link
Owner Author

@stewartknapman stewartknapman commented Aug 7, 2019

@jjp2133 It’s hard for me to tell exactly what’s going on without seeing the code. Can you post the contents of your snippet so I can have a look?

@blueseanj

This comment has been minimized.

Copy link

@blueseanj blueseanj commented Aug 18, 2019

Hi I tried to use this version of the accordion and the previous one on my shopify but couldnt work. it shows liquid error on my product page. Im using Brooklyn theme, any help on the path of where to place those files snippets/assets/templates/ etc ? That would be really helpful! Thanks.

@googula

This comment has been minimized.

Copy link

@googula googula commented Nov 19, 2019

Can this change accordion change to all close and only open when its click?
like your previous accordion

@jschuler00

This comment has been minimized.

Copy link

@jschuler00 jschuler00 commented Mar 17, 2021

Where are the icon include files?

@stewartknapman

This comment has been minimized.

Copy link
Owner Author

@stewartknapman stewartknapman commented Mar 18, 2021

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

This comment has been minimized.

Copy link

@edwardboyce edwardboyce commented May 18, 2021

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