Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Tabbed Product description snippet for Shopify
{% comment %}
if combine_pretext is false, the text before the first <h6> will be shown above all tabs, otherwise added to the first tab
{% endcomment %}
{% assign combine_pretext = false %}
{% assign description = tabbed-description | default: product.description %}
{% if description contains "<h6>" %}
{% assign tab_heads = '' %}
{% assign tab_texts = '' %}
{% assign pretext = '' %}
{% assign chunks = description | strip | split: "<h6>" %}
{% for c in chunks %}
{% if c contains "</h6>" %}
{% assign chunk = c | split: "</h6>" %}
{% assign tab_heads = tab_heads | append: ",," | append: chunk.first %}
{% assign tab_texts = tab_texts | append: ",," %}
{% if pretext != blank and combine_pretext %}
{% assign tab_texts = tab_texts | append: pretext | append: "<br>" %}
{% assign pretext = '' %}
{% endif %}
{% assign tab_texts = tab_texts | append: chunk.last %}
{% elsif forloop.first %}
{% assign pretext = c %}
{% endif %}
{% endfor %}
{% assign tab_heads = tab_heads | remove_first: ",," | split: ",," %}
{% assign tab_texts = tab_texts | remove_first: ",," | split: ",," %}
{% assign index = 1 %}
<div>
{% if pretext != blank and combine_pretext == false %}
<span class=pretext>{{ pretext }}</span>
{% endif %}
<ul class="tabs">
{% for head in tab_heads %}
<li><a href="#tab-{{- index -}}">{{ head }}</a></li>
{% assign index = index | plus: 1 %}
{% endfor %}
</ul>
{% assign index = 1 %}
{% for text in tab_texts %}
<div id="tab-{{- index -}}">{{ text }}</div>
{% assign index = index | plus: 1 %}
{% endfor %}
</div>
<script>
document.addEventListener( 'DOMContentLoaded', function () {
function findTabContent( link ){
if( link && link.nodeName == "A" ){
var contentID = link.attributes.href.value.replace('#','');
return document.getElementById( contentID );
}
else
return null;
}
function hide( element ){
if( element )
element.style.display="none";
}
function show( element ){
if( element )
element.style.display="";
}
function setActive( element ){
if( element ){
element.classList.add('active');
var c = findTabContent( element );
show(c);
}
}
var tabHeads = Array.from( document.getElementsByClassName('tabs') );
tabHeads.forEach( function( tablist ){
var links = document.querySelectorAll('.tabs a'),
tabs = document.querySelectorAll('.tabs li');
if( links.length == 0 )
return;
var active = links[0],
content = findTabContent( active ),
totalWidth = 0, currentMode;
setActive( active );
links.forEach( function( el, index ){
if( index > 0 )
hide( findTabContent( el ) );
});
/* event listener for clicking tabs */
tablist.addEventListener( 'click', function(e){
var clicked = e.target;
if( clicked.nodeName !== "A" )
return;
e.preventDefault();
active.classList.remove('active');
hide( content );
active = clicked;
content = findTabContent( clicked );
setActive( clicked );
return false;
});
function onResize( e ){
if( e.type == 'load' ){
/* how wide are all our tab headers together? calculate this once, on load */
tabs.forEach( function( el, i ) {
totalWidth += el.offsetWidth ;
});
}
/* will they fit on one line? check on every resize/rotate */
if( tablist.clientWidth > totalWidth ){
if( currentMode !== 'wide' ) {
tablist.classList.remove('vertical');
currentMode = 'wide';
}
} else{
if( currentMode !== 'narrow' ) {
tablist.classList.add('vertical');
currentMode = 'narrow';
}
}
}
window.addEventListener( 'resize', onResize );
window.addEventListener( 'load', onResize );
});
});
</script>
<style>
ul.tabs {
border-bottom: 1px solid #DDDDDD;
display: block;
margin: 0 0 20px;
padding: 0;
}
ul.tabs li {
display: block;
float: left;
height: 30px;
margin-bottom: 0;
padding: 0;
width: auto;
}
ul.tabs li a {
-moz-border-bottom-colors: none;
-moz-border-image: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background: none repeat scroll 0 0 #F5F5F5;
border-color: #DDDDDD !important;
border-style: solid;
border-width: 1px 1px 0 1px;
display: block;
font-size: 13px;
height: 29px;
line-height: 30px;
margin: 0;
padding: 0 20px;
text-decoration: none;
width: auto;
color: #303030;
border-bottom:none !important;
}
ul.tabs li a.active {
background: none repeat scroll 0 0 #FFFFFF;
border-left-width: 1px;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
color: #111111;
height: 30px;
margin: 0 0 0 -1px;
padding-top: 4px;
position: relative;
top: -4px;
}
ul.tabs li:first-child a.active {
margin-left: 0;
}
ul.tabs li:first-child a {
border-top-left-radius: 2px;
border-width: 1px 1px 0;
}
ul.tabs li:last-child a {
border-top-right-radius: 2px;
}
ul.tabs:before, ul.tabs:after {
content: " ";
display: block;
height: 0;
overflow: hidden;
visibility: hidden;
width: 0;
}
ul.tabs:after {
clear: both;
}
/* update for better mobile look */
ul.tabs.vertical> li {
width: 100%;
}
</style>
{% else %}
{{ description }}
{% endif %}
@OkayDokayOkay

This comment has been minimized.

Copy link

@OkayDokayOkay OkayDokayOkay commented May 18, 2020

Hello,
I am using this code for my shop - works great.
However, when I am changing the styling, e.g. background color when tab active from #FFFFFF to #ff0266 for example, nothing changes.
It seems like something is overwriting my styling - how can I fix this?
Best,
OKAY

@davidkensell

This comment has been minimized.

Copy link

@davidkensell davidkensell commented Nov 15, 2020

Would be amazing to have a Vanilla JS version of this. Shopify's putting a lot of emphasis on page speed, jQuery has fallen out of favor.

@tairli

This comment has been minimized.

Copy link
Owner Author

@tairli tairli commented Jan 18, 2021

Vanilla JS version is here :)

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