Adding Product Description Tabs to Shopify

Adding Product Description Tabs to Shopify

April 22, 2016 | | No Comments

We were working on a Shopify project recently where the client requested we add in description tabs for their product pages. By default, Shopify allows for a product description to be added manually and will be placed where specified based on the liquid template layout. There aren’t any options built in to the Shopify CMS that allow for tabs to be added (understandably as this is a very specific request) so this is something we needed to build out custom for the client. The client would also be managing the product listings themselves so we needed to create something that was somewhat reproducible.

The person managing the site is familiar enough with basic HTML and a text editor which is really all they would need. Everything on the client side will be done via the Shopify product admin screen. I would NOT recommend this manner of implementation for an individual that is not at least entry-level familiar with basic HTML syntax but in our case it works out for the client.

To start you will need: familiarity with Shopify’s Liquid templating system and mid-level jQuery knowledge. I will explain why I use certain pieces of code but not necessarily go in-depth as to how each piece works as it is beyond the scope of this article. Shopify has great documentation for familiarizing yourself with their templating system. I would recommend looking thru it in order for the Shopify part to make more sense. So without further ado…

Setting Up Your Template

The only template we will really need to edit in this case is the product.liquid template used to display our products. If your theme uses a different file then that’s what you will edit but for the most part standard Shopify themes will use this file for product display.

The existing product information is shown in the right column of the product page while the product image is displayed on the left. There is an area under all of the content where recommended products will show. The description tabs we will be including will go in between the product area and the recommended products list.


In our product.liquid template we will need to add a container DIV that will receive the information we are taking from our description and display as tabs. We look for the closing DIVs for our product description/image area and the opening DIV for our related products area and place our container DIV in between.

<div class="product-description rte" itemprop="description">
{{ product.description }}

{% if settings.social_sharing_products %}
{% include 'social-sharing' %}
{% endif %}

<div class="grid">
<div class="grid-item large--full tabs-container"></div>
{% if settings.related_products_enable %}
{% assign grid_item_width = 'large--one-fifth medium--one-third small--one-half' %}
{% include 'related-products' %}
{% endif %}

The “grid” class creates a new row and the “grid-item large–full” tells our template that this will be a full-width section within the row. The class “tabs-container” is used as the DIV identifier which we will use later on.

Adding the Product Description

In the product description we are going to add in the content we will be displaying in the tabs but without any type of formatting. This information will also be hidden using CSS. It’s VERY important that the formatting for the div be done correctly as this will determine how we pull the info that will go into our tabs.

In the product description area on the product edit screen in Shopify switch to HTML mode by clicking the icon with the “<>” icons. This will change your edit screen from WYSIWYG to HTML. This is very important as the information we are entering into our description needs to be HTML and not formatted with the WYSIWYG editor.

Ideally this information will be entered below the actual description you want displayed on the product page. This will make it easier for your client to differentiate between actual content and tabs content that is hidden. For our example we will be using three DIVs and using their pre-made names as identifiers in our Javascript. DIVs are as follows:

<p class="normal">Product description content goes here</p>
<!-- begin tabs content -->
<div class="tabs-content__placeholder" id="tab-content__how-to-use" data-title="How to Use">
<p>These are the instructions for how to use the items in this product.</p>
<div class="tabs-content__placeholder" id="tab-content__cautions" data-title="Cautions">
<p>These are the cautions</p>
<div class="tabs-content__placeholder" id="tab-content__ingredients" data-title="Ingredients">
<p>These are the ingredients</p>
<!-- end tabs content -->

PLEASE NOTE: Our naming convention in this case is used for the client’s convenience. Ideally, this would be made so that you can create as many tabs as you’d like and cycle thru them programmatically with JS. But for my client’s purposes it’s better (and more convenient) for them if I use very specific DIV names as to avoid confusion when creating these later. If you are a little unclear as to what I mean take a minute to look over the DIVs we are adding and you will see what I am talking about.

In this case we are creating three DIVs for three tabs. The general class we are assigning to each div is “tabs-content__placeholder” and each of these has a unique ID. The div also has a data attribute for “title”. The content that goes in these divs can be any standard HTML and is the information that we will be updating on a per-product basis. This is the same format we will be using for all of the tabs on all of our products. I would recommend keeping the code snippet somewhere handy where you can copy/paste it in to your product description and just update the content as this is something that we will be using over and over when adding them to all of our products. For our purposes in this tutorial this is the only time you will see this code.

Setting Up Your Javascript

Essentially what we will be doing to create the tabs without the need for a dedicated CMS field in Shopify is “moving” the content from the product description to the tabs container we created in our template field. We are going to do this with a little bit of Javascript.

Back in our product.liquid template, scroll all the way to the bottom until you see the beginning of the template’s Javascript section. Look for the opening jQuery wrapper opening tag as this is where our JS is going to go. In our theme this was the code:

jQuery(function($) {
new Shopify.OptionSelectors('productSelect', {
product: {{ product | json }},
onVariantSelected: selectCallback,
enableHistoryState: true

Your JS will go somewhere inside of the wrapper. Placement is really up to you. I opted to place it at the end, right before the closing tag for organizational purposes. We will start by creating the function that we call later on to begin moving the content from the product description to the container div:

var createTabs = function() {
var $tabContainer = $('.tabs-container');

We begin by creating the function and defining our container variable. In this case I used ‘$tabContainer’.

Next, create an array that contains the information for each of the tabs we will be creating:

var $tabContent = {
'how-to-use': {
'content': $('#tab-content__how-to-use').html(),
'title': $('#tab-content__how-to-use').data('title')
'cautions': {
'content': $('#tab-content__cautions').html(),
'title': $('#tab-content__cautions').data('title')
'ingredients': {
'content': $('#tab-content__ingredients').html(),
'title': $('#tab-content__ingredients').data('title')

There are two items being created for each array item: a key and an additional array that contains the ‘content’ and the ‘title’. The key is used to target our specific tabs later on when clicking the tabs you want to use to display your content. The content is the tab content itself and the title is the text we will be using on the tab. This content is coming from the divs that we added to our product description earlier. We are targeting them using the unique ID we assigned to each one. The title comes from the data attribute that was added to each one.

Next, create a new variable for the tabs and the content divs.

var $tabs = '<ul class="tabs clearfix">';
var $content = '';

$tabs is where we are going to be adding our tabs and content is where we are adding the content of each of the divs in our product description. Add a counter variable as well:

var $counter = 0;

This will let us determine the starting tab that will be active when the page initially loads.

Now, map through your array and begin building the tabs and content.

$.map($tabContent, function(v, k) {
if ($counter == 0) {
var active = ' active';
} else {
var active = '';
if (v.content) {
$tabs += '<li class="tabs-button ' + active + '" data-target="' + k + '-tab">' + v.title + '</li>';
$content += '<div class="tabs-content ' + active + '" id="' + k + '-tab">' + v.content + '</div>';
$tabs += '</ul>';

Let’s explain what is happening here. We are using ‘$counter’ to determine if we are at the beginning of our array. If we are, we assign a value of ‘active’ to our active variable. If not, we leave the variable empty. Next, we determine if there is content in this particular array item. If there is, we add a LI to the $tabs variable. If not, we move on to the next array item. The LI we are creating has a class (‘tabs-button’), an ‘active’ class if we are at the beginning of the array, a ‘data-target’ attribute which is the content div that the tab will show when clicked, and title text.

For the content we are creating a new div with class ‘tabs-content’ and ‘active’ if it’s the first item in the array. The div also has a unique ID that will be determined by the array item’s key (k). This div is added to our $content variable.

Once done we increment the value of $counter.

After our mapping is done we add a close ‘ul’ tag to our $tabs variable.

Once this is complete, add in the $tabs and $content to the tab container and close the function:

$tabContainer.html($tabs + $content);

Once we save our file and refresh our product page we should see text in between the description area and the recommended products. It will be regular text just floating on its own but we will format it with CSS in the next step. The text is also duplicated in the product description but we will remove it later.

Formatting Tabs with CSS

Open your theme’s main SCSS liquid file. In our theme I have a unique SCSS file I use in order to avoid overwriting the Timber SCSS file but you can do it in whatever manner is convenient.

We will start by hiding the tab content in our product description:

.tabs-content__placeholder {
display: none;

Next, format your tabs so that they are the full width of the content area and have a border at the bottom. In our SCSS file, $colorPrimary is the primary color that is selected in the Shopify theme options.

.tabs {
width: 100%;
clear: both;
border-bottom: 1px solid $colorPrimary;
margin-bottom: 20px;
margin-top: 40px;

Format the tabs themselves. Since we are using a uniform list you will need to float each of the items left so they are inline. Add borders and a cursor as well.

.tabs-button {
float: left;
border-left: 1px solid lightgrey;
border-right: 1px solid lightgrey;
border-top: 1px solid lightgrey;
padding: 10px 20px;
border-radius: 3px 3px 0 0;
margin-right: 2px;
margin-bottom: 0;
cursor: pointer;

Our ‘active’ button will be that one that applies to the currently visible tab. The background color will be our theme’s primary color and the text color will be white. If you are using a very light color as your theme color then you may want to make the text color something dark to contrast. We are also changing our border colors to match.

&.active {
background: $colorPrimary;
border-left: 1px solid $colorPrimary;
border-right: 1px solid $colorPrimary;
border-top: 1px solid $colorPrimary;
color: #ffffff;
font-weight: bold;

Hide all of the ‘tabs-content’ divs and make the ‘active’ one visible.

.tabs-content {
display: none;
&.active {
display: block;

Once formatting is complete your tabs should look the way you intended although they won’t exactly work yet.


Putting Those Tabs to Work!

What good are tabs if they don’t actually function, well, like tabs. Let’s go back to our product.liquid template and add in our tab code. This will go right after our closing bracket for the createTabs function:

$(document).ready(function() {
if ($('.tabs-content__placeholder').length) {
$('.tabs-button').click(function() {
var target = $(this).data('target');
$('#' + target ).addClass('active');

The first thing we do is check to see if we have tab content in our product description. If we don’t, we skip right over the tab process altogether. If we do, begin by calling our createTabs() function. Then, assign a click event handler to each of ‘.tabs-button’ object. The target of the tab will be the ‘target’ data attribute. We then remove the ‘active’ class from the current active tab and active tab content. Then we add an ‘active’ class to the target content div and the tab we just clicked on.

And that’s it! We now have fully functioning tabs. All you or your client need to do to update is add in the formatted divs to the product description and javascript will take care of the rest.

You can view a full pen with adapted code here. Feel free to shoot us an email if you have any questions about this or other related items. Thanks for reading!

Share this article: