Great follow-up! Let’s get this working for you. 
The issue is likely down to the use of {{image1}}, {{image2}}, etc. — these look like template tags, but inside the HTML Component in Elements, Alpine.js expects actual URLs as strings or (if you want to get fancy) you need to pass in image property values from a custom component the right way.
Here’s how to fix it:
Scenario 1: Just use image URLs directly
Replace your Alpine code block like this:
<div x-data="{ selected: 0, images: [
'/images/photo1.jpg',
'/images/photo2.jpg',
'/images/photo3.jpg',
'/images/photo4.jpg'
]}">
<!-- Main image display -->
<img
:src="images[selected]"
alt="Main Product"
class="w-full h-80 object-cover rounded shadow mb-4 transition-all duration-300"
>
<!-- Thumbnails row -->
<div class="flex gap-2">
<template x-for="(img, idx) in images" :key="idx">
<button
@click="selected = idx"
:aria-current="selected === idx"
class="border-2 rounded w-20 h-20 overflow-hidden border-transparent focus:outline-none focus:ring-2 focus:ring-blue-400"
:class="selected === idx ? 'border-blue-500 ring-2 ring-blue-400' : 'border-gray-200'"
>
<img :src="img" alt="" class="object-cover w-full h-full"/>
</button>
</template>
</div>
</div>
Swap out /images/photo1.jpg etc for your actual image files.
No curly braces or template tags — just plain old strings!
Scenario 2: You want it to be a reusable component
If you want to use component properties (so you get nice image wells in the sidebar), you need to make a custom properties file (with groups/properties), and reference those in your HTML like this:
properties.json example:
{
"groups": [
{
"label": "Gallery Images",
"properties": [
{
"type": "image",
"id": "img1",
"label": "Image 1"
},
{
"type": "image",
"id": "img2",
"label": "Image 2"
},
{
"type": "image",
"id": "img3",
"label": "Image 3"
},
{
"type": "image",
"id": "img4",
"label": "Image 4"
}
]
}
]
}
Inside your HTML Component, set up Alpine like this:
<div x-data="{ selected: 0, images: [
'{{img1}}',
'{{img2}}',
'{{img3}}',
'{{img4}}'
]}">
<!-- The rest stays the same -->
<img
:src="images[selected]"
alt="Main Product"
class="w-full h-80 object-cover rounded shadow mb-4 transition-all duration-300"
>
<div class="flex gap-2">
<template x-for="(img, idx) in images" :key="idx">
<button
@click="selected = idx"
:aria-current="selected === idx"
class="border-2 rounded w-20 h-20 overflow-hidden border-transparent focus:outline-none focus:ring-2 focus:ring-blue-400"
:class="selected === idx ? 'border-blue-500 ring-2 ring-blue-400' : 'border-gray-200'"
>
<img :src="img" alt="" class="object-cover w-full h-full"/>
</button>
</template>
</div>
</div>
Make sure you fill in each “Image” property with an actual image in Elements.
Gotcha to Avoid:
- If a property is empty (no image chosen),
{{img3}} will literally output as an empty string. So check you provided an image for every slot, or trim down the array.
Troubleshooting checklist:
- Are the image URLs correct and accessible by the browser?
- Did you publish or preview with the correct image paths?
- Did you fill in custom properties, if using them?
If you want, I’ll post a complete step-by-step for building a drag-n-drop reusable Gallery Component the “Elements way.” Just say the word!
(And hey, you’re already miles ahead of the old Stacks method.
)
Let me know if you get it working, or shout if you need a hand!