(()=>{for(const root of document.querySelectorAll('[data-snippet="property-feature-gallery"]')){if(root.dataset.initialized)continue;root.dataset.initialized='true';const pictures=[{"src":"images/coast.webp","caption":"Rocky coast beside open water"},{"src":"images/passage.webp","caption":"Escalator lights inside a station"},{"src":"images/boathouse.webp","caption":"Boathouse reflected in still water"},{"src":"images/venice.webp","caption":"Canal and buildings in Venice"},{"src":"images/forest.webp","caption":"Lake reflected between forest trees"},{"src":"images/blue-hour.webp","caption":"Lakeside cabin below mountains at dusk"}];const dialog=root.querySelector('dialog');let current=0,last=null;const show=i=>{current=(i+pictures.length)%pictures.length;const p=pictures[current],img=dialog.querySelector('img');img.src=p.src;img.alt=p.caption;dialog.querySelector('figcaption').textContent=p.caption;root.querySelector('[data-image-count]').textContent=(current+1)+' / '+pictures.length;};root.addEventListener('click',e=>{const a=e.target.closest('[data-gallery-index]');if(a&&!e.ctrlKey&&!e.metaKey&&typeof dialog.showModal==='function'){e.preventDefault();last=a;show(Number(a.dataset.galleryIndex));dialog.showModal();}});dialog.querySelector('[data-close]').addEventListener('click',()=>dialog.close());dialog.addEventListener('close',()=>last?.focus());dialog.querySelector('[data-prev]').addEventListener('click',()=>show(current-1));dialog.querySelector('[data-next]').addEventListener('click',()=>show(current+1));dialog.addEventListener('keydown',e=>{if(e.key==='ArrowRight'){e.preventDefault();show(current+1);}if(e.key==='ArrowLeft'){e.preventDefault();show(current-1);}});for(const btn of root.querySelectorAll('[data-image-choice]'))btn.addEventListener('click',()=>{const i=Number(btn.dataset.imageChoice),p=pictures[i],main=root.querySelector('.s-product-main'),img=main.querySelector('img');img.src=p.src;img.alt=p.caption;main.querySelector('a').href=p.src;main.querySelector('a').dataset.galleryIndex=i;main.querySelector('figcaption').textContent=p.caption;root.querySelectorAll('[data-image-choice]').forEach(b=>b.setAttribute('aria-pressed',String(b===btn)));});}})();
---
// Generated, escaped static markup. Use a distinct prefix for each instance.
const markup = "\u003csection class=\"fct-property-feature-gallery s-gallery-section s-property\" data-snippet=\"property-feature-gallery\" aria-labelledby=\"fct-property-feature-gallery-heading\"\u003e\u003cdiv class=\"s-wrap\"\u003e\u003cp class=\"s-kicker\"\u003eA closer look\u003c/p\u003e\u003ch2 id=\"fct-property-feature-gallery-heading\"\u003ePlaces worth a second look.\u003c/h2\u003e\u003cp class=\"s-gallery-intro\"\u003eLicensed illustrative photographs. Replace these with your own images and descriptions.\u003c/p\u003e\u003cdiv class=\"s-gallery\"\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/coast.webp\" data-gallery-index=\"0\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/coast.webp\" alt=\"Rocky coast beside open water\" width=\"800\" height=\"600\" loading=\"eager\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eRocky coast beside open water\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/passage.webp\" data-gallery-index=\"1\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/passage.webp\" alt=\"Escalator lights inside a station\" width=\"800\" height=\"600\" loading=\"lazy\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eEscalator lights inside a station\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/boathouse.webp\" data-gallery-index=\"2\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/boathouse.webp\" alt=\"Boathouse reflected in still water\" width=\"800\" height=\"600\" loading=\"lazy\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eBoathouse reflected in still water\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/venice.webp\" data-gallery-index=\"3\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/venice.webp\" alt=\"Canal and buildings in Venice\" width=\"800\" height=\"600\" loading=\"lazy\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eCanal and buildings in Venice\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/forest.webp\" data-gallery-index=\"4\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/forest.webp\" alt=\"Lake reflected between forest trees\" width=\"800\" height=\"600\" loading=\"lazy\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eLake reflected between forest trees\u003c/figcaption\u003e\u003c/figure\u003e\u003cfigure class=\"\"\u003e\u003ca href=\"/snippet-assets/property-feature-gallery/images/blue-hour.webp\" data-gallery-index=\"5\"\u003e\u003cimg src=\"/snippet-assets/property-feature-gallery/images/blue-hour.webp\" alt=\"Lakeside cabin below mountains at dusk\" width=\"800\" height=\"600\" loading=\"lazy\" decoding=\"async\"\u003e\u003c/a\u003e\u003cfigcaption\u003eLakeside cabin below mountains at dusk\u003c/figcaption\u003e\u003c/figure\u003e\u003c/div\u003e\u003cdialog aria-label=\"Enlarged image\" class=\"s-lightbox\"\u003e\u003cbutton type=\"button\" data-close\u003eClose\u003c/button\u003e\u003cfigure\u003e\u003cimg alt=\"\" width=\"800\" height=\"600\"\u003e\u003cfigcaption\u003e\u003c/figcaption\u003e\u003c/figure\u003e\u003cdiv class=\"s-lightbox-controls\"\u003e\u003cbutton type=\"button\" data-prev\u003ePrevious\u003c/button\u003e\u003cspan role=\"status\" data-image-count\u003e\u003c/span\u003e\u003cbutton type=\"button\" data-next\u003eNext\u003c/button\u003e\u003c/div\u003e\u003c/dialog\u003e\u003c/div\u003e\u003c/section\u003e";
---
<Fragment set:html={markup} />
<style is:global>
.fct-property-feature-gallery{--s-bg:#162e42;--s-ink:#ffffff;--s-accent:#e0bd80;font:16px/1.65 system-ui,sans-serif;color:var(--s-ink);background:var(--s-bg)}.fct-property-feature-gallery,.fct-property-feature-gallery *{box-sizing:border-box}.fct-property-feature-gallery :is(h2,h3,p,ul,figure){margin:0}.fct-property-feature-gallery h2,.fct-property-feature-gallery h3{line-height:1.2;letter-spacing:-.035em}.fct-property-feature-gallery h2{font-size:clamp(1.8rem,4vw,3.5rem)}.fct-property-feature-gallery a{color:inherit;text-underline-offset:5px;overflow-wrap:anywhere}.fct-property-feature-gallery :is(a,button,input,textarea,select,summary):focus-visible{outline:3px solid var(--s-accent);outline-offset:4px}.fct-property-feature-gallery button,.fct-property-feature-gallery input,.fct-property-feature-gallery textarea,.fct-property-feature-gallery select{font:inherit}.fct-property-feature-gallery a,.fct-property-feature-gallery button{touch-action:manipulation}.fct-property-feature-gallery .s-wrap{max-width:1200px;margin-inline:auto;padding:40px 28px}.fct-property-feature-gallery .s-kicker{font-size:.8125rem;letter-spacing:.13em;text-transform:uppercase;margin-bottom:18px}.fct-property-feature-gallery .s-button{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:11px 21px;border:1px solid currentColor;text-decoration:none;background:transparent;color:inherit;cursor:pointer;border-radius:2px;font-weight:600}.fct-property-feature-gallery .s-muted{opacity:.82}.fct-property-feature-gallery .s-links{display:flex;gap:8px 26px;flex-wrap:wrap}.fct-property-feature-gallery .s-links a{display:inline-flex;align-items:center;min-height:44px}.fct-property-feature-gallery .s-rule{border-top:1px solid currentColor;padding-top:20px;margin-top:30px}.fct-property-feature-gallery .s-grid{display:grid;gap:28px;grid-template-columns:repeat(3,minmax(0,1fr))}.fct-property-feature-gallery img{max-width:100%;height:auto;display:block}.fct-property-feature-gallery .s-brand{font-size:1.3rem;font-weight:700;letter-spacing:-.05em;text-decoration:none}@media(max-width:640px){.fct-property-feature-gallery .s-wrap{padding:30px 20px}.fct-property-feature-gallery .s-grid{grid-template-columns:1fr}}
.fct-property-feature-gallery .s-gallery-intro{margin:22px 0 35px;max-width:62ch}.fct-property-feature-gallery .s-gallery{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px}.fct-property-feature-gallery .s-gallery figure{min-width:0}.fct-property-feature-gallery .s-gallery a{display:block}.fct-property-feature-gallery .s-gallery img{width:100%;aspect-ratio:4/3;object-fit:cover}.fct-property-feature-gallery figcaption{font-size:.875rem;line-height:1.6;padding-top:12px}.fct-property-feature-gallery.s-story .s-gallery{grid-template-columns:repeat(2,minmax(0,1fr));gap:40px}.fct-property-feature-gallery.s-story .s-gallery figure:first-child{grid-column:1/-1;max-width:850px}.fct-property-feature-gallery.s-story h2{font-family:Georgia,serif;font-weight:400}.fct-property-feature-gallery.s-property .s-gallery{grid-template-columns:repeat(4,minmax(0,1fr));gap:15px}.fct-property-feature-gallery.s-property .s-gallery figure:first-child{grid-column:1/-1}.fct-property-feature-gallery.s-property .s-gallery figure:first-child img{aspect-ratio:2/1}.fct-property-feature-gallery.s-contact-sheet .s-gallery{grid-template-columns:repeat(4,minmax(0,1fr));gap:18px}.fct-property-feature-gallery.s-contact-sheet figure{border-top:1px solid currentColor;padding-top:14px}.fct-property-feature-gallery.s-contact-sheet figcaption{font-family:ui-monospace,monospace}.fct-property-feature-gallery .s-product-main{max-width:850px;margin:auto}.fct-property-feature-gallery .s-product-main img{width:100%;max-height:520px;object-fit:cover}.fct-property-feature-gallery .s-thumbnails{display:flex;flex-wrap:wrap;gap:14px;margin:28px 0;justify-content:center}.fct-property-feature-gallery .s-thumbnails button{padding:4px;border:1px solid currentColor;background:transparent;cursor:pointer;width:112px;min-height:44px}.fct-property-feature-gallery .s-thumbnails button[aria-pressed=true]{outline:3px solid var(--s-accent);outline-offset:2px}.fct-property-feature-gallery .s-thumbnails img{width:100%;height:75px;object-fit:cover}.fct-property-feature-gallery dialog{max-width:min(1000px,calc(100vw - 30px));max-height:calc(100dvh - 30px);border:1px solid #64705a;padding:20px;background:#fff;color:#232b22}.fct-property-feature-gallery dialog :is(button,a):focus-visible{outline:3px solid #3c5929;outline-offset:3px}.fct-property-feature-gallery dialog::backdrop{background:#101810dc}.fct-property-feature-gallery dialog[open]{display:flex;flex-direction:column;gap:15px}.fct-property-feature-gallery dialog img{max-height:65dvh;max-width:100%;width:auto;margin:auto;object-fit:contain}.fct-property-feature-gallery dialog button{min-height:44px;padding:10px 18px;border:1px solid #56664a;background:#fff;color:#232b22;cursor:pointer}.fct-property-feature-gallery dialog [data-close]{align-self:end}.fct-property-feature-gallery .s-lightbox-controls{display:flex;align-items:center;justify-content:space-between;gap:20px}.fct-property-feature-gallery dialog figure{margin:0}@media(max-width:800px){.fct-property-feature-gallery .s-gallery,.fct-property-feature-gallery.s-property .s-gallery,.fct-property-feature-gallery.s-contact-sheet .s-gallery{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:480px){.fct-property-feature-gallery .s-gallery,.fct-property-feature-gallery.s-story .s-gallery,.fct-property-feature-gallery.s-property .s-gallery,.fct-property-feature-gallery.s-contact-sheet .s-gallery{grid-template-columns:1fr}.fct-property-feature-gallery .s-lightbox-controls{gap:10px;font-size:.875rem}}
</style>
<script is:inline>
(()=>{for(const root of document.querySelectorAll('[data-snippet="property-feature-gallery"]')){if(root.dataset.initialized)continue;root.dataset.initialized='true';const pictures=[{"src":"/snippet-assets/property-feature-gallery/images/coast.webp","caption":"Rocky coast beside open water"},{"src":"/snippet-assets/property-feature-gallery/images/passage.webp","caption":"Escalator lights inside a station"},{"src":"/snippet-assets/property-feature-gallery/images/boathouse.webp","caption":"Boathouse reflected in still water"},{"src":"/snippet-assets/property-feature-gallery/images/venice.webp","caption":"Canal and buildings in Venice"},{"src":"/snippet-assets/property-feature-gallery/images/forest.webp","caption":"Lake reflected between forest trees"},{"src":"/snippet-assets/property-feature-gallery/images/blue-hour.webp","caption":"Lakeside cabin below mountains at dusk"}];const dialog=root.querySelector('dialog');let current=0,last=null;const show=i=>{current=(i+pictures.length)%pictures.length;const p=pictures[current],img=dialog.querySelector('img');img.src=p.src;img.alt=p.caption;dialog.querySelector('figcaption').textContent=p.caption;root.querySelector('[data-image-count]').textContent=(current+1)+' / '+pictures.length;};root.addEventListener('click',e=>{const a=e.target.closest('[data-gallery-index]');if(a&&!e.ctrlKey&&!e.metaKey&&typeof dialog.showModal==='function'){e.preventDefault();last=a;show(Number(a.dataset.galleryIndex));dialog.showModal();}});dialog.querySelector('[data-close]').addEventListener('click',()=>dialog.close());dialog.addEventListener('close',()=>last?.focus());dialog.querySelector('[data-prev]').addEventListener('click',()=>show(current-1));dialog.querySelector('[data-next]').addEventListener('click',()=>show(current+1));dialog.addEventListener('keydown',e=>{if(e.key==='ArrowRight'){e.preventDefault();show(current+1);}if(e.key==='ArrowLeft'){e.preventDefault();show(current-1);}});for(const btn of root.querySelectorAll('[data-image-choice]'))btn.addEventListener('click',()=>{const i=Number(btn.dataset.imageChoice),p=pictures[i],main=root.querySelector('.s-product-main'),img=main.querySelector('img');img.src=p.src;img.alt=p.caption;main.querySelector('a').href=p.src;main.querySelector('a').dataset.galleryIndex=i;main.querySelector('figcaption').textContent=p.caption;root.querySelectorAll('[data-image-choice]').forEach(b=>b.setAttribute('aria-pressed',String(b===btn)));});}})();
</script>
Where this design fits
The first view receives more space, while secondary views sit in a separate grid. This is a gallery presentation, not a property listing backend or booking system.
Wide feature view
Supporting image grid
Lightbox navigation
What is included
The HTML ZIP includes a standalone demo, reusable markup, scoped CSS, its small JavaScript runtime, a license and setup notes. The Astro ZIP includes Snippet.astro, local sample images and image credits. It can be imported into an existing Astro page or layout.
Replace the sample photographs
Included photographs are licensed illustrative assets. They are not work created by the demonstration business. Update image paths, dimensions, captions and alternative descriptions for your own files. The ZIP includes the original image-source and license notes.
Add it to an HTML website
Copy snippet.html into the relevant page section.
Load snippet.css after your existing site stylesheet. The class prefix identifies this design.
Load snippet.js once with defer. Keep the included keyboard behavior when adapting interactions.
Replace example content and check mobile widths, zoom, links and keyboard focus in your actual website.
Use it in Astro
Copy Snippet.astro into src/components/, import it into your page or shared layout, and insert the component where the section belongs. Copy images into public/snippet-assets/property-feature-gallery/images; the component uses that public path. Keep each generated prefix unique if you duplicate a component on one page.
Keep the section maintainable
Start with the variables at the top of the CSS for background, text and accent colors. Preserve semantic labels and focus styles. Existing site selectors can still affect imported markup, so test the combined result. Read the complete setup notes.