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