Skip to content

Instantly share code, notes, and snippets.

@Juandresyn
Created November 22, 2021 16:12
Show Gist options
  • Save Juandresyn/1d0b13488e63deda987515bce7eca7b5 to your computer and use it in GitHub Desktop.
Save Juandresyn/1d0b13488e63deda987515bce7eca7b5 to your computer and use it in GitHub Desktop.
Pure JS shopify ready accordion
{%- comment -%}
Available Variables
* id: The accordion id
* content: The tab content
* color: The color for h4 headings, borders, and icons
* number: Display the number for the tab
{%- endcomment -%}
{% if color == blank %}
{% assign color = '#3200B2' %}
{% endif %}
<ul id="{{ id }}" class='{{ class }}'>
{{ content }}
</ul>
{% style %}
{% if numbers %}
#{{ id }} {
counter-reset: {{ id }}listCounter;
}
#{{ id }} > li {
counter-increment: {{ id }}listCounter;
padding-left: 40px;
position: relative;
}
#{{ id }} > li::before {
content: counter({{ id }}listCounter);
color: {{ color }};
font-size: 14px;
font-weight: 400;
position: absolute;
left: 0;
top: 32px;
border: 2px solid {{ color }};
line-height: 0;
border-radius: 50%;
width: 26px;
height: 26px;
display: flex;
justify-content: center;
align-items: center;
transition: background-color 0.2s ease-in-out;
background-color: var(--color-white);
}
#{{ id }} > .is--active::before {
background-color: {{ color }};
color: var(--color-white);
}
{% endif %}
#{{ id }} > li h4 {
color: {{ color }};
cursor: pointer;
position: relative;
margin-bottom: 32px;
}
#{{ id }} > li h4::after,
#{{ id }} > li h4::before {
position: absolute;
content: '';
background-image: url("data:image/svg+xml,%3Csvg width='18' height='2' viewBox='0 0 18 2' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1H17' stroke='%23{{ color | remove: '#' }}' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
display: inline-block;
width: 16px;
height: 2px;
right: 0;
top: calc(50% - 1px);
}
#{{ id }} > li h4::before {
transform: rotate(90deg);
transition: transform 0.2s ease-in-out;
}
#{{ id }} .is--active > h4::before {
transform: rotate(0deg);
}
#{{ id }} .is--active > h4 + div {
opacity: 1;
margin-bottom: 20px;
}
#{{ id }} > li {
border-bottom: 1px solid {{ color }};
}
{% endstyle %}
<script>
(function(){
const d = document;
const ul = d.querySelector('#{{ id }}');
const h4s = d.querySelectorAll('#{{ id }} > li h4');
const activeClass = 'is--active'
ul.addEventListener('click', function(e) {
const target = e.target;
if (target && target.nodeName == 'H4') {
const targetIsActive = target.parentElement.classList.value.includes(activeClass);
const itemContent = target.nextElementSibling;
for (let i = 0; i < h4s.length; i++) {
// Close everything
h4s[i].parentElement.classList.remove(activeClass);
h4s[i].nextElementSibling.style.height = '0';
}
// Open the clicked item if it does not have active class
if (!targetIsActive) {
target.parentElement.classList.add(activeClass);
target.nextElementSibling.style.height = itemContent.dataset.realHeight + 'px';
}
}
});
const initReset = function(e) {
for (let i = 0; i < h4s.length; i++) {
const itemContent = h4s[i].nextElementSibling;
// Reset content height css param
itemContent.style.height = '';
// Store in a data attr the real height of the content
itemContent.dataset.realHeight = itemContent.offsetHeight;
// Make it 0 at the beginning for collapsed effect.
itemContent.style.height = '0';
// Make the first item active
if (i === 0) {
h4s[i].parentElement.classList.add(activeClass);
itemContent.style.height = itemContent.dataset.realHeight + 'px';
}
}
}
document.addEventListener("DOMContentLoaded", initReset);
window.addEventListener("resize", initReset);
})();
</script>
{%- comment -%}
Available Variables
* title: The tab title
* content: The tab content
{%- endcomment -%}
<li class="pt-8">
<h4>{{ title }}</h4>
<div class="transition-all duration-300 ease overflow-hidden">
{{ content }}
</div>
</li>
<div id="{{ section.id }}" class="flex flex-col py-20 my-2 lg:py-[110px] lg:justify-between lg:flex-row border-t border-b border-transparent lg:border-0">
<div class="w-full lg:w-1/3">
<h2 class="heading--{{ section.id }} uppercase lg:mt-7 lg:mb-6 text-[32px] hidden lg:block" style="color: {{ section.settings.title_color }}">{{ section.settings.title }}</h2>
</div>
<div class="w-full lg:w-1/2">
{%- capture accordionItems -%}
{% for block in section.blocks %}
{% assign content = block.settings.content %}
{% if block.settings.content_page != blank %}
{% assign content = pages[block.settings.content_page].content %}
{% endif %}
{% render 'accordion_item', title: block.settings.title, content: content %}
{% endfor %}
{%- endcapture -%}
{% render 'accordion', id: section.id, content: accordionItems, numbers: section.settings.accordion_numbers, color: section.settings.accordion_color %}
</div>
</div>
{% style %}
#{{ section.id }} {
border-color: {{ section.settings.accordion_color }};
}
{% endstyle %}
{% schema %}
{
"name": "Faqs",
"settings": [
{
"type": "text",
"id": "title",
"label": "Title"
},
{
"type": "color",
"id": "title_color",
"label": "Title Color",
"default": "#000000"
},
{
"type": "color",
"id": "accordion_color",
"label": "Main color for borders & titles",
"default": "#3200B2",
"info": "Preferably a color according to our [design system](https://www.figma.com/file/jjOXQ7wz1RCG1CYzF9Cdpw/Yellowpop-Website---Hand-Off?node-id=1%3A2)"
},
{
"type": "checkbox",
"id": "accordion_numbers",
"label": "Show number on items?",
"default": false
}
],
"blocks": [
{
"type": "accordion_item",
"name": "Accordion Item",
"settings": [
{
"type": "text",
"id": "title",
"label": "Title"
},
{
"type": "richtext",
"id": "content",
"label": "Content"
},
{
"type": "page",
"id": "content_page",
"label": "Show page as content",
"info": "If a page is selected the 'Content' value will be ignored"
}
]
}
],
"presets": [
{
"name": "Faqs",
"category": "Information"
}
]
}
{% endschema %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment