Creating a Dynamic Product Carousel Using Section Blocks

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

Introduction

A compelling product carousel immediately grabs attention and highlights key products, boosting conversions in your Shopify store. By leveraging Shopify 2.0’s section blocks, you can create a dynamic, merchant-friendly carousel that allows store owners to easily add, reorder, and customize slides directly from the theme editor, without needing to write code. This guide will teach you how to build a carousel that enhances the user experience and improves sales.

Man working on e-commerce website design on a laptop.

Understanding Section Blocks for Carousels

With block-based carousels you get: Dynamic Management where merchants can add or remove slides easily in the theme editor; Custom Settings per Slide such as unique images, headlines, and buttons for each block; easy Reordering with drag-and-drop functionality to change slide order without coding; and Preset Configurations to provide default slides for an out-of-the-box ready carousel.

What Are Section Blocks?

Shopify 2.0 enables sections on every page and introduces blocks—repeatable, draggable items within a section. Blocks are ideal for carousels because each slide can be a block with its own settings (image, heading, link).

  • Dynamic Management: Merchants can add or remove slides in the theme editor.
  • Custom Settings per Slide: Unique images, headlines, buttons per block.
  • Reorder Easily: Drag-and-drop to change slide order without touching code.
  • Preset Configurations: Provide default slides via presets so the carousel looks ready out of the box.

Prerequisites and Setup

  1. Shopify 2.0 Theme: Ensure your theme supports JSON templates and sections.
  2. Shopify CLI: For local development (shopify theme serve).
  3. Code Editor: VS Code or similar, with Liquid support.
  4. Basic JavaScript & CSS: Familiarity with event listeners and transforms.

Initialize your theme locally:

bashCopyEditshopify login --store your-dev-store.myshopify.com
shopify theme init my-carousel-theme
cd my-carousel-theme
shopify theme serve

Create a new file at sections/product-carousel.liquid. Begin with the boilerplate:

Customer browsing products on a tablet for a seamless online experience.
liquidCopyEdit{% schema %}
{
  "name": "Product Carousel",
  "max_blocks": 8,
  "blocks": [
    {
      "type": "slide",
      "name": "Slide",
      "settings": [
        {
          "type": "product",
          "id": "product",
          "label": "Select Product"
        },
        {
          "type": "image_picker",
          "id": "image",
          "label": "Custom Slide Image (optional)"
        },
        {
          "type": "text",
          "id": "heading",
          "label": "Slide Heading",
          "default": ""
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Default Carousel",
      "category": "Featured"
    }
  ]
}
{% endschema %}
  • max_blocks limits slides to 8.
  • blocks array defines each slide’s settings: picking a product, optional override image, and heading.
  • presets seeds a default empty carousel in new themes.

Above the schema, add markup that loops through each block:

liquidCopyEdit<div class="carousel" data-carousel>
  <div class="carousel__track">
    {% for block in section.blocks %}
      {% assign prod = all_products[block.settings.product] %}
      <div class="carousel__slide" data-slide-index="{{ forloop.index0 }}">
        <a href="{{ prod.url }}" class="carousel__link">
          <img
            src="{{ block.settings.image | img_url: '800x' | default: prod.featured_image | img_url: '800x' }}"
            alt="{{ block.settings.heading | default: prod.title }}"
            class="carousel__image"
          >
        </a>
        <div class="carousel__caption">
          <h3>{{ block.settings.heading | default: prod.title }}</h3>
          <p>{{ prod.price | money }}</p>
        </div>
      </div>
    {% endfor %}
  </div>
  <button class="carousel__prev" aria-label="Previous slide">‹</button>
  <button class="carousel__next" aria-label="Next slide">›</button>
</div>
  • .carousel__track: Flex container for slides.
  • data- attributes: Used to initialize JS behavior.
  • Image source: Uses custom image if set, else product’s featured image.
  • Caption: Heading and price pulled dynamically.

Step 3: Styling with CSS

Add styles in assets/product-carousel.css:

cssCopyEdit.carousel {
  position: relative;
  overflow: hidden;
}
.carousel__track {
  display: flex;
  transition: transform 0.5s ease;
}
.carousel__slide {
  min-width: 100%;
  box-sizing: border-box;
  position: relative;
}
.carousel__image {
  width: 100%;
  display: block;
}
.carousel__caption {
  position: absolute;
  bottom: 1rem;
  left: 1rem;
  background: rgba(0,0,0,0.5);
  color: #fff;
  padding: 0.5rem 1rem;
  border-radius: 4px;
}
.carousel__prev,
.carousel__next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0,0,0,0.5);
  border: none;
  color: #fff;
  font-size: 2rem;
  padding: 0 0.5rem;
  cursor: pointer;
}
.carousel__prev { left: 0.5rem; }
.carousel__next { right: 0.5rem; }

Include the stylesheet in your layout:

liquidCopyEdit{{ 'product-carousel.css' | asset_url | stylesheet_tag }}

Step 4: Adding JavaScript for Interactivity

Create `assets/product-carousel.js` to handle the carousel’s interactive behavior. Use JavaScript event listeners to detect when the page is loaded, then select all elements with the `data-carousel` attribute to initialize the carousel functionality. By using JavaScript, you can create dynamic transitions, button-controlled navigation, and improve the user experience. Don’t forget to include the stylesheet in your layout under. Consider exploring JavaScript frameworks for advanced carousel features.

Various products arranged on shelves, emphasizing a curated product showcase.
jsCopyEditdocument.addEventListener('DOMContentLoaded', () => {
  const carousels = document.querySelectorAll('[data-carousel]');
  carousels.forEach(initCarousel);
});

function initCarousel(carousel) {
  const track = carousel.querySelector('.carousel__track');
  const slides = Array.from(track.children);
  const prevButton = carousel.querySelector('.carousel__prev');
  const nextButton = carousel.querySelector('.carousel__next');
  let currentIndex = 0;

  function updateTrack() {
    const offset = -currentIndex * carousel.clientWidth;
    track.style.transform = `translateX(${offset}px)`;
  }

  prevButton.addEventListener('click', () => {
    currentIndex = (currentIndex - 1 + slides.length) % slides.length;
    updateTrack();
  });
  nextButton.addEventListener('click', () => {
    currentIndex = (currentIndex + 1) % slides.length;
    updateTrack();
  });

  // Optional autoplay
  let autoplay = carousel.dataset.autoplay === 'true';
  if (autoplay) {
    setInterval(() => {
      nextButton.click();
    }, parseInt(carousel.dataset.autoplayInterval, 10) || 5000);
  }

  // Resize handler
  window.addEventListener('resize', updateTrack);
}

Include it in your layout under <body>:

liquidCopyEdit{{ 'product-carousel.js' | asset_url | script_tag }}
  • updateTrack() shifts slides via CSS transforms.
  • Autoplay support via data-autoplay and data-autoplay-interval attributes.
  • Responsive: Recalculates positions on resize.

Step 5: Exposing Autoplay Settings (Optional)

Allow merchants to toggle autoplay and interval via section settings. In your schema’s root:

jsonCopyEdit"settings": [
  {
    "type": "checkbox",
    "id": "autoplay",
    "label": "Enable Autoplay",
    "default": true
  },
  {
    "type": "number",
    "id": "autoplay_interval",
    "label": "Autoplay Interval (ms)",
    "min": 2000,
    "max": 10000,
    "step": 500,
    "default": 5000
  }
]

In the markup wrapper:

liquidCopyEdit<div
  class="carousel"
  data-carousel
  data-autoplay="{{ section.settings.autoplay }}"
  data-autoplay-interval="{{ section.settings.autoplay_interval }}"
>

Merchants can now control autoplay behavior directly in the theme editor.

Conclusion

Person analyzing digital marketing data on a laptop screen.

Creating a dynamic product carousel using Shopify 2.0 section blocks integrates Liquid, CSS, and JavaScript for a flexible, user-friendly component. By defining block-based slides, crafting responsive styles, and wiring up interactive behavior, you empower merchants with a drag-and-drop carousel they can manage without code. Layer in optional autoplay settings and thoughtful defaults via JSON templates for a polished, easily maintainable solution.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts