Shopify themes, liquid, logos, and UX
Hi there,
I used below code to get a smooth opening of the accordions however this somehow prevented me from clicking on any navigation buttons/search button.
Is there a better code to achieve this than below?
THanks!
class Accordion {
constructor(el) {
this.el = el;
this.summary = el.querySelector('summary');
this.content = el.querySelector('.accordion__content') || el.querySelector('.content');
this.animation = null;
this.isClosing = false;
this.isExpanding = false;
this.summary.addEventListener('click', (e) => this.onClick(e));
}
onClick(e) {
e.preventDefault();
this.el.style.overflow = 'hidden';
if (this.isClosing || !this.el.open) {
this.open();
} else if (this.isExpanding || this.el.open) {
this.shrink();
}
}
shrink() {
this.isClosing = true;
const startHeight = `${this.el.offsetHeight}px`;
const endHeight = `${this.summary.offsetHeight}px`;
if (this.animation) {
this.animation.cancel();
}
this.animation = this.el.animate({
height: [startHeight, endHeight]
}, {
duration: 500,
easing: 'ease-in'
});
this.animation.onfinish = () => this.onAnimationFinish(false);
this.animation.oncancel = () => this.isClosing = false;
}
open() {
this.el.style.height = `${this.el.offsetHeight}px`;
this.el.open = true;
window.requestAnimationFrame(() => this.expand());
}
expand() {
this.isExpanding = true;
const startHeight = `${this.el.offsetHeight}px`;
const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`;
if (this.animation) {
this.animation.cancel();
}
this.animation = this.el.animate({
height: [startHeight, endHeight]
}, {
duration: 400,
easing: 'ease-out'
});
this.animation.onfinish = () => this.onAnimationFinish(true);
this.animation.oncancel = () => this.isExpanding = false;
}
onAnimationFinish(open) {
this.el.open = open;
this.animation = null;
this.isClosing = false;
this.isExpanding = false;
this.el.style.height = '';
this.el.style.overflow = '';
}
}
document.querySelectorAll('details').forEach((el) => {
new Accordion(el);
});
Solved! Go to the solution
This is an accepted solution.
This is because navigation and search popup use details elements too.
You should try limiting your code to accordions inside main template area, by changing the bottom part of your code like this:
document.querySelectorAll('main details').forEach((el) => {
new Accordion(el);
});
This would only target details inside template and not in header or overlays. Like product page accordions or faqs...
This is an accepted solution.
This is because navigation and search popup use details elements too.
You should try limiting your code to accordions inside main template area, by changing the bottom part of your code like this:
document.querySelectorAll('main details').forEach((el) => {
new Accordion(el);
});
This would only target details inside template and not in header or overlays. Like product page accordions or faqs...
thanks for explaining, that worked perfectly!
@tim I've added a code now so only one accordion panel remains open at a time, but it's kinda glitchy (the text of both tabs overlaps for a second when they open/close). Would there be a better solution for this?
The reason is because you're animating height of details but it does not always have overflow: hidden set -- you set it in OnClick, but not in shrink, which is what you call directly when another accordion is being opened.
Moving this.el.style.overflow = "hidden" into shrink and open should solve the problem.
Now, the theme does some JS processing on these as well, so there may be interference also (say, aria stuff may be messed up when you directly manipulate open attribute).
I, myself would rather use CSS only approach, something like https://developer.mozilla.org/en-US/docs/Web/CSS/::details-content#transition_example
Learn how to build powerful custom workflows in Shopify Flow with expert guidance from ...
By Jacqui May 7, 2025Did You Know? May is named after Maia, the Roman goddess of growth and flourishing! ...
By JasonH May 2, 2025Discover opportunities to improve SEO with new guidance available from Shopify’s growth...
By Jacqui May 1, 2025