• i only speak liquid
  • Posts
  • "i only speak liquid" #93: You’ve Been Building Slider Sections Wrong

"i only speak liquid" #93: You’ve Been Building Slider Sections Wrong

Written by Brandon (a Storetasker Expert)

Hey everyone,

Exciting day today: We have a NEW guest writer for “i_only_speak_liquid”.

Brandon is a talented developer based in Canada. His specialty is in geeking out on the many customisations available via Shopify. When he’s not deep in code, Brandon’s usually solving bouldering problems.

He’s an expert on Storetasker 😉 (apply here) and you can stay in touch with him here.

Let’s dive in 🤿

But wait before we do: I want to give a shout out to our partners at Hookdeck. Their team has built a tool for Shopify developers like y’all. Here’s what it’s all about:

Losing webhooks? Reclaim your sanity with Hookdeck 

Webhook issues led to customer complaints. Don’t let the next flash sale or bulk operation from your biggest merchant take down your app. Sound familiar?

Hookdeck Event Gateway acts as a middleware between Shopify webhooks and your app. It automatically queues webhooks, managing spikes and warning you of issues.

With a persistent event log, you can inspect, retry, and debug any webhooks.

Best of all, no code changes or background jobs required; just update your webhook URLs to get up to 10k free events per month.

What I’ve been thinking about:

Undisputedly, the way Shopify themes are built has changed throughout the years. Most notably, Shopify released nested groups and blocks last year. Now that we’ve had a few months to let the dust settle, and I’ve had some time to experiment, I’ll share how I’ve been building custom slider sections.

Part 1: Library

An extremely underrated JS library I found is Blaze Sliders. I came across this library in a YCombinator forum and can’t figure out why it hasn’t been adopted more recently. It’s lightweight (2kb gzipped), uses CSS strategically to prevent CLS issues, and only does what you need it to do with clean animations.

I’ll include a link below, among other options. However, sometimes the best slider isn’t the most powerful one but rather the smallest, most focused tool that does exactly what your project needs and nothing more.

Part 2: Structure


The structure I follow is as follows:

  1. Section: The container for the slider that mainly controls width

  2. Layout: The interactive slider that holds cards

  3. Card: The container for all of the content, which controls layout

  4. Block (Optional): The content e.g. text, buttons, images, etc…

Besides the visual above, I’ll include some code below for all of the liquid nerds out there.

sections/custom-slider.liquid

<div id="{{ section.id }}" class="custom-slider">
  <h1></h1>
  <div class="custom-slider__blocks">
    {% content_for 'blocks' %}
  </div>
</div>

{
 "name": "Custom Slider",
 "blocks": [{ "type": "layout-slider" }],
 "settings": [
    { "type": "text", "id": "title", "label": "Title", "default": "Custom Slider" }
  ]
}

blocks/layout-slider.liquid

<div id="{{ block.id }}" class="layout-slider" >
  <div class="blaze-slider">
    <div class="blaze-container">
      <div class="arrow-controls">
        <button class="blaze-prev"></button>
        <button class="blaze-next"></button>
      </div>
      <div class="blaze-track-wrapper">
        <div class="blaze-track">
          {% content_for 'blocks' %}
        </div>
      </div>
    </div>
  </div>
</div>

{
  "name": "Layout (slider)",
  "blocks": [{ "type": "custom-slider-card" }],
  "settings": [
    {
      "type": "html",
      "id": "arrow",
      "label": "Arrow",
      "default": "<svg>...</svg>"
    }
  ]
}

/blocks/custom-slider-card

{%- liquid
  assign blockid = block.id
  assign image = block.settings.image
  assign link = block.settings.link
  assign border_radius = block.settings.border_radius
  assign title = block.settings.title
  assign description = block.settings.description
  assign product = block.settings.product
-%}

<div id="" class="image-block" >
  <a href="" class="card-link">
    {% if image != blank %}
      image_tag: loading: 'lazy', alt: image.alt
    {% else %}
      <div class="image-placeholder" style="aspect-ratio: 1; background: #eee;"></div>
    {% endif %}
    <div class="card-content">
      <h3></h3>
      <p class="card-price">money</p>
      <p></p>
    </div>
  </a>
</div>

Part 3: Functionality

Blaze needs a single container element per slider. You initialize it in a {% javascript %} block. To support multiple sliders on the same page, scope the script to the block’s wrapper (e.g. by block.id) instead of document.querySelector('.blaze-slider') so each section block gets its own instance:

{% javascript %}
document.addEventListener('DOMContentLoaded', function () {
 const container = document.getElementById('{{ block.id }}');
 const el = container.querySelector('.blaze-slider');

 new BlazeSlider(el, {
    all: {
      slidesToShow: 3.2,
      loop: false,
      prevArrow: el.querySelector('.blaze-prev'),
      nextArrow: el.querySelector('.blaze-next'),
    },
 '(max-width: 768px)': { slidesToShow: 2.2 },
 '(max-width: 425px)': { slidesToShow: 1.2 },
  });
});
{% endjavascript %}

Note: Responsive behavior is configured via Blaze’s breakpoint options, so you don’t need separate CSS for “how many slides show.”

Flexi: An app I’ve been building for almost two years that lets me drop professionally built sections into any client project. I got tired of rebuilding the same sections over and over, so I turned my workflow into a system I can reuse across sites.

Slider libraries I reference when building sections:

Blaze Sliders (referenced in this article)

Swiper Sliders (alternative option)

Flickity Sliders (alternative option)

One learning as a freelancer:

Sometimes what clients are really paying for is the least risky option. Not the cheapest, not the fastest but the person who feels calm, clear, and predictable. I’ve won contracts simply by clearly outlining the risks of the other options my client was considering.