← Go back

Shopify Image & Text Sync Section – Interactive & Responsive

: Create an engaging Shopify section that syncs images with corresponding text dynamically. This interactive layout ensures smooth transitions and user-friendly navigation. Fully customizable and mobile-responsive.

Preview Password = 1 *When you first time enter them back again then click agian Preview to show*
Liquid Code
                    <!-- 
========================================
Section Name: Image & Text Sync Section
Tech Stack: Liquid, JavaScript (Splide.js), HTML, CSS
What This Section Does: 
- Dynamically syncs images with corresponding text content.
- Ensures smooth transitions between slides with interactive animations.
- Fully responsive for both desktop and mobile users.

Promotion: 
This Shopify section is designed to enhance user engagement by linking text with images dynamically. It’s a fully customizable and mobile-responsive solution available on [PrebuiltTemplates](https://prebuilttemplates.com/).
========================================
-->
<section class="custom-image-text-sync" style="background-color: {{ section.settings.background_color }}; padding: {{ section.settings.padding_top }}px 0 {{ section.settings.padding_bottom }}px;">
  <div class="custom-container page-width">
    <div class="custom-grid">
      <!-- Left Column: Text Content -->
      <div class="custom-text-content">
        {% for block in section.blocks %}
          <div class="text-block {% if forloop.first %}active{% endif %}" data-index="{{ forloop.index0 }}">
            {% if block.settings.caption != blank %}
              <p class="caption">{{ block.settings.caption }}</p>
            {% endif %}
            {% if block.settings.title != blank %}
              <h2 class="title">{{ block.settings.title }}</h2>
            {% endif %}
            {% if block.settings.text != blank %}
              <p class="description">{{ block.settings.text }}</p>
            {% endif %}
          </div>
        {% endfor %}
      </div>

      <!-- Right Column: Splide Image Slider -->
      <div class="custom-slider-container">
        <div class="splide" id="custom-slider">
          <div class="splide__track">
            <ul class="splide__list">
              {% for block in section.blocks %}
                {% if block.settings.image != blank %}
                  <li class="splide__slide" data-index="{{ forloop.index0 }}">
                    <img src="{{ block.settings.image |  img_url: 'master' }}" alt="Slider Image" />
                  </li>
                {% endif %}
              {% endfor %}
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<style>
.custom-image-text-sync {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.custom-container {
  max-width: 1200px;
  width: 100%;
}

.custom-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  align-items: center;
}

.custom-text-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.text-block {
  display: none;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.text-block.active {
  display: block;
  opacity: 1;
  transform: translateY(0);
}

.custom-text-content .caption {
  font-size: 14px;
  font-weight: 600;
  color: #008060;
  text-transform: uppercase;
}

.custom-text-content .title {
  font-size: 32px;
  font-weight: bold;
  color: #044f2b;
  margin: 10px 0;
}

.custom-text-content .description {
  font-size: 16px;
  color: #444;
  line-height: 1.5;
}

/* Splide Slider */
.custom-slider-container {
  position: relative;
  width: 100%;
}

.splide__slide img {
    width: 100%;
    height: 560px;
    object-fit: cover;
    display: block;
    border-radius: 10px;
}

/* Responsive */
@media (max-width: 768px) {
  .custom-grid {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .custom-text-content {
    text-align: center;
  }
}
</style>

<!-- Include Splide.js -->
<script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@latest/dist/js/splide.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@latest/dist/css/splide.min.css">

<script>
document.addEventListener("DOMContentLoaded", function () {
  var splide = new Splide("#custom-slider", {
    type: "loop",
    perPage: 1,
    pagination: true,
    arrows: false,
    autoplay: false,
    interval: 3000,
  });

  splide.on("move", function (index) {
    let textBlocks = document.querySelectorAll(".text-block");

    // Hide all text blocks first
    textBlocks.forEach((block) => {
      block.classList.remove("active");
      block.style.opacity = "0";  // Start hiding
      block.style.transform = "translateY(20px)";
    });

    // Delay to apply display: none; only for non-active elements
    setTimeout(() => {
      textBlocks.forEach((block) => {
        if (parseInt(block.getAttribute("data-index")) !== index) {
          block.style.display = "none";
        }
      });

      // Show the new active block
      let activeText = document.querySelector(`.text-block[data-index="${index}"]`);
      if (activeText) {
        activeText.style.display = "block";

        requestAnimationFrame(() => {
          activeText.classList.add("active");
          activeText.style.opacity = "1";  
          activeText.style.transform = "translateY(0)";
        });
      }
    }, 300); // Delay for smooth hiding before displaying the next block
  });

  splide.mount();
});

</script>

{% schema %}
{
  "name": "Image Text Sync",
  "settings": [
    {
      "type": "color",
      "id": "background_color",
      "label": "Background Color",
      "default": "#f9f9f9"
    },
    {
      "type": "range",
      "id": "padding_top",
      "label": "Padding Top",
      "default": 50,
      "min": 0,
      "max": 200,
      "step": 5
    },
    {
      "type": "range",
      "id": "padding_bottom",
      "label": "Padding Bottom",
      "default": 50,
      "min": 0,
      "max": 200,
      "step": 5
    }
  ],
  "blocks": [
    {
      "type": "content",
      "name": "Content Block",
      "settings": [
        {
          "type": "text",
          "id": "caption",
          "label": "Caption",
          "default": "Surf Proof!"
        },
        {
          "type": "text",
          "id": "title",
          "label": "Title",
          "default": "The perfect swim bottoms"
        },
        {
          "type": "textarea",
          "id": "text",
          "label": "Text",
          "default": "The perfect swim bottoms combine both comfort and style, offering a secure fit for swimming and water activities while also showcasing a fashionable design."
        },
        {
          "type": "image_picker",
          "id": "image",
          "label": "Image"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Image Text Sync",
      "category": "Custom Sections"
    }
  ]
}
{% endschema %}