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.
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 %}