I do not know what you’re asking here. Are you asking if I tested the code that Wes provided? If so, I answered that and it resulted in multiple errors and did not function.
I had others reaching out via DMs and such, even after requesting that all communication remain here so the public can see the results. After receiving AI-type responses from many, rather than useful information, I decided to take another whack at it. I wanted to edit what was already available, but decided best to start from scratch. The code below was added and works well-enough, and includes a few backend features most won’t notice. It isn’t the prettiest and I’m certain there’s much better ways to accomplish this task, but it functions and I can now move onto more pressing matters - like getting paid.
{% schema %}
{
“name”: “Custom Slideshow”,
“settings”: [
{ "type": "number", "id": "interval", "label": "Autoplay interval (ms)", "default": 5000 },
{ "type": "number", "id": "fade_duration", "label": "Fade duration (ms)", "default": 800 },
{ "type": "checkbox", "id": "pause_on_hover", "label": "Pause on hover", "default": true },
{
"type": "select",
"id": "lazy_behavior",
"label": "Lazy-load behavior",
"options": \[
{ "value": "preload_neighbors", "label": "Preload neighbors (recommended)" },
{ "value": "nearby_only", "label": "Load when near viewport" },
{ "value": "none", "label": "No lazy loading (load all immediately)" }
\],
"default": "preload_neighbors"
},
{
"type": "select",
"id": "image_format",
"label": "Prefer image format",
"options": \[
{ "value": "auto", "label": "Auto (AVIF -> WebP -> original)" },
{ "value": "webp", "label": "WebP preferred" },
{ "value": "avif", "label": "AVIF preferred" },
{ "value": "none", "label": "No format preference (original files only)" }
\],
"default": "auto"
}
],
“blocks”: [
{
"type": "slide",
"name": "Slide",
"settings": \[
{ "type": "image_picker", "id": "desktop_image", "label": "Desktop image" },
{ "type": "image_picker", "id": "mobile_image", "label": "Mobile image" },
{ "type": "url", "id": "link", "label": "Link URL" },
{ "type": "text", "id": "alt_text", "label": "Alt text", "default": "Slide image" }
\]
}
],
“presets”: [{ “name”: “Custom Slideshow”, “category”: “Hero” }]
}
{% endschema %}
{% comment %}
Server-side: generate explicit variant URLs per width for each slide using Shopify img_url.
WIDTH list: 280,320,360,420,480,640,750,900,1000,1280,1600,2048
{% endcomment %}
{% for block in section.blocks %}
{% assign d = block.settings.desktop_image %}
{% assign m = block.settings.mobile_image %}
{% assign slide_href = block.settings.link | default: "" %}
<div
class="cs-slide"
data-href="{{ slide_href | escape }}"
role="link"
aria-label="{{ block.settings.alt_text }}"
data-index="{{ forloop.index0 }}"
tabindex="0"
{% comment %} store master references for client-side logic if needed {% endcomment %}
>
<picture
data-srcsets='{
"desktop": {
"280":"{{ d | img_url: '280x' }}",
"320":"{{ d | img_url: '320x' }}",
"360":"{{ d | img_url: '360x' }}",
"420":"{{ d | img_url: '420x' }}",
"480":"{{ d | img_url: '480x' }}",
"640":"{{ d | img_url: '640x' }}",
"750":"{{ d | img_url: '750x' }}",
"900":"{{ d | img_url: '900x' }}",
"1000":"{{ d | img_url: '1000x' }}",
"1280":"{{ d | img_url: '1280x' }}",
"1600":"{{ d | img_url: '1600x' }}",
"2048":"{{ d | img_url: '2048x' }}"
},
"mobile": {
"280":"{{ m | img_url: '280x' }}",
"320":"{{ m | img_url: '320x' }}",
"360":"{{ m | img_url: '360x' }}",
"420":"{{ m | img_url: '420x' }}",
"480":"{{ m | img_url: '480x' }}",
"640":"{{ m | img_url: '640x' }}",
"750":"{{ m | img_url: '750x' }}",
"900":"{{ m | img_url: '900x' }}",
"1000":"{{ m | img_url: '1000x' }}",
"1280":"{{ m | img_url: '1280x' }}",
"1600":"{{ m | img_url: '1600x' }}",
"2048":"{{ m | img_url: '2048x' }}"
}
}'
>
<!-- mobile source placeholder (filled by JS when loading) -->
<source media="(max-width: 749px)" data-srcset-mobile>
<!-- img placeholder -->
<img data-src-desktop alt="{{ block.settings.alt_text }}" loading="lazy" decoding="async">
</picture>
</div>
{% endfor %}
.custom-slideshow { position: relative; width: 100%; overflow: hidden; touch-action: pan-y; -ms-touch-action: pan-y; user-select: none; }
.custom-slideshow .cs-slide { position: absolute; inset: 0; display: block; opacity: 0; transition: opacity calc(var(--fade,800ms)) ease-in-out; -webkit-tap-highlight-color: transparent; cursor: pointer; }
.custom-slideshow .cs-slide img { width: 100%; height: auto; display: block; object-fit: cover; pointer-events: none; user-select: none; }
.custom-slideshow .cs-slide.is-active { opacity: 1; position: relative; z-index: 2; }
.custom-slideshow .cs-slide:not(.is-active) { pointer-events: none; z-index: 1; }
.custom-slideshow { --fade: {{ section.settings.fade_duration }}ms; }
@media (max-width: 749px) { .custom-slideshow { height: auto; } }