Account Settings
FIRST NAME
[Loading...]
LAST NAME
[Loading...]
EMAIL
[Loading...]
ID
[Loading...] For support purposes only
Share AgencyGenius

Step 1: Add HTML, Css & JavaScript

Code
Html
Css
Javascript
Combined
 <!-- 
 Image Cycling Widget - Start 
 This is a self-contained widget that cycles through images automatically 
 when in viewport. The widget has smooth transitions between images. 
 --> 
 <div id="unique-image-cycler-widget"> 
 <div class="image-cycle-collection"> 
 <div class="image-cycle-collection__before"></div> 
 <div class="image-cycle-collection__list" data-image-cycle> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macos-sonoma-wallpapers-5120x2160-v0-j9vwvbq8h5wb1.jpg" loading="lazy" alt="macOS Sonoma Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macOS-Mojave-Day-wallpaper.jpg" loading="lazy" alt="macOS Mojave Day Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/da68i50-00fbde21-b0fa-49cc-a0ca-cdebca7b0730.jpg" loading="lazy" alt="macOS Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macos-big-sur-ysfrml6k0il45zd8.jpg" loading="lazy" alt="macOS Big Sur Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/mountain-scenery-macos-4k-wallpaper-uhdpaper.com-106-0-h.jpg" loading="lazy" alt="Mountain Scenery macOS Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/mountain-scenery-macos-4k-wallpaper-uhdpaper.com-108-0-h.jpg" loading="lazy" alt="Mountain Scenery macOS Wallpaper 2"> 
 </div> 
 </div> 
 </div> 
 </div> 
 <!-- Image Cycling Widget - End --> 
 /* Main container styling */ 
 #unique-image-cycler-widget { 
 width: 100%; 
 max-width: 100%; 
 height: 100%; 
 } 
  
 /* Image cycle collection container */ 
 #unique-image-cycler-widget .image-cycle-collection { 
 width: 100%; 
 height: 100%; 
 position: relative; 
 } 
  
 /* Creates aspect ratio space holder */ 
 #unique-image-cycler-widget .image-cycle-collection__before { 
 padding-top: 50%; /* Default aspect ratio, container can override */ 
 } 
  
 /* Image list container */ 
 #unique-image-cycler-widget .image-cycle-collection__list { 
 z-index: 0; 
 border-radius: 10px; 
 width: 100%; 
 height: 100%; 
 position: absolute; 
 top: 0; 
 left: 0; 
 overflow: hidden; 
 } 
  
 /* Image item positioning */ 
 #unique-image-cycler-widget .image-cycle-collection__img { 
 width: 100%; 
 height: 100%; 
 position: absolute; 
 top: 0; 
 left: 0; 
 object-fit: cover; 
 } 
  
 /* Image inside container */ 
 #unique-image-cycler-widget .image-cycle-collection__img img { 
 width: 100%; 
 height: 100%; 
 object-fit: cover; 
 } 
  
 /* Active image state */ 
 #unique-image-cycler-widget [data-image-cycle-item="active"] { 
 transition: opacity 0.4s ease 0s, visibility 0s ease 0s; 
 opacity: 1; 
 visibility: visible; 
 z-index: 3; 
 } 
  
 /* Previous image state (fading out) */ 
 #unique-image-cycler-widget [data-image-cycle-item="previous"] { 
 transition: opacity 0.4s ease 0.4s, visibility 0s ease 0.4s; 
 opacity: 0; 
 visibility: visible; 
 z-index: 2; 
 } 
  
 /* Inactive image state */ 
 #unique-image-cycler-widget [data-image-cycle-item="not-active"] { 
 opacity: 0; 
 visibility: hidden; 
 z-index: 1; 
 } 
  
 /* Responsive adjustments for mobile */ 
 @media screen and (max-width: 767px) { 
 #unique-image-cycler-widget .image-cycle-collection__list { 
 border-radius: 10px; /* Maintain 10px radius on mobile */ 
 } 
 } 
 // Self-executing function to avoid global scope pollution 
 (function() { 
 // Initialize when DOM is fully loaded 
 document.addEventListener('DOMContentLoaded', function() { 
 initImageCycle(); 
 }); 
  
 /** 
 * Initialize image cycling functionality 
 * Finds all image cycle containers and sets up automatic cycling 
 */ 
 function initImageCycle() { 
 // Find all image cycle containers within our widget 
 const widgetContainer = document.getElementById('unique-image-cycler-widget'); 
 const cycleElements = widgetContainer.querySelectorAll("[data-image-cycle]"); 
  
 cycleElements.forEach(cycleElement => { 
 // Get all items in this cycle group 
 const items = cycleElement.querySelectorAll("[data-image-cycle-item]"); 
  
 // Skip if there aren't enough items to cycle 
 if (items.length < 2) return; 
  
 let currentIndex = 0; 
 let intervalId; 
 const duration = 2000; // Time between transitions in milliseconds 
 const isTwoItems = items.length === 2; 
  
 // Initialize: First item active, others not-active 
 items.forEach((item, i) => { 
 item.setAttribute("data-image-cycle-item", i === 0 ? "active" : "not-active"); 
 }); 
  
 /** 
 * Cycle to the next image in the collection 
 */ 
 function cycleImages() { 
 const prevIndex = currentIndex; 
 currentIndex = (currentIndex + 1) % items.length; 
  
 if (isTwoItems) { 
 // Special case: Only two images - toggle between "previous" and "active" 
 items[prevIndex].setAttribute("data-image-cycle-item", "previous"); 
 } else { 
 // Normal case: Three or more images 
 items[prevIndex].setAttribute("data-image-cycle-item", "previous"); 
  
 // Set to not-active after transition completes 
 setTimeout(() => { 
 items[prevIndex].setAttribute("data-image-cycle-item", "not-active"); 
 }, duration); 
 } 
  
 // Set new active item 
 items[currentIndex].setAttribute("data-image-cycle-item", "active"); 
 } 
  
 // Use IntersectionObserver to start/stop cycling when in/out of viewport 
 const observer = new IntersectionObserver(([entry]) => { 
 if (entry.isIntersecting && !intervalId) { 
 // Start cycling when element is visible 
 intervalId = setInterval(cycleImages, duration); 
 } else if (!entry.isIntersecting && intervalId) { 
 // Stop cycling when element is not visible 
 clearInterval(intervalId); 
 intervalId = null; 
 } 
 }, { threshold: 0 }); 
  
 // Start observing the element 
 observer.observe(cycleElement); 
 }); 
 } 
 })(); 
 <div id="snippet-zl1ztacc"> 
 <!-- HTML SECTION START --> 
 <!-- 
 Image Cycling Widget - Start 
 This is a self-contained widget that cycles through images automatically 
 when in viewport. The widget has smooth transitions between images. 
 --> 
 <div id="unique-image-cycler-widget"> 
 <div class="image-cycle-collection"> 
 <div class="image-cycle-collection__before"></div> 
 <div class="image-cycle-collection__list" data-image-cycle> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macos-sonoma-wallpapers-5120x2160-v0-j9vwvbq8h5wb1.jpg" loading="lazy" alt="macOS Sonoma Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macOS-Mojave-Day-wallpaper.jpg" loading="lazy" alt="macOS Mojave Day Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/da68i50-00fbde21-b0fa-49cc-a0ca-cdebca7b0730.jpg" loading="lazy" alt="macOS Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/macos-big-sur-ysfrml6k0il45zd8.jpg" loading="lazy" alt="macOS Big Sur Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/mountain-scenery-macos-4k-wallpaper-uhdpaper.com-106-0-h.jpg" loading="lazy" alt="Mountain Scenery macOS Wallpaper"> 
 </div> 
 <div class="image-cycle-collection__img" data-image-cycle-item> 
 <img src="https://irp.cdn-website.com/a778beb9/dms3rep/multi/mountain-scenery-macos-4k-wallpaper-uhdpaper.com-108-0-h.jpg" loading="lazy" alt="Mountain Scenery macOS Wallpaper 2"> 
 </div> 
 </div> 
 </div> 
 </div> 
 <!-- Image Cycling Widget - End --> 
 <!-- HTML SECTION END --> 
  
 <!-- CSS SECTION START --> 
 <style> 
 /* Main container styling */ 
 #unique-image-cycler-widget { 
 width: 100%; 
 max-width: 100%; 
 height: 100%; 
 } 
  
 /* Image cycle collection container */ 
 #unique-image-cycler-widget .image-cycle-collection { 
 width: 100%; 
 height: 100%; 
 position: relative; 
 } 
  
 /* Creates aspect ratio space holder */ 
 #unique-image-cycler-widget .image-cycle-collection__before { 
 padding-top: 50%; /* Default aspect ratio, container can override */ 
 } 
  
 /* Image list container */ 
 #unique-image-cycler-widget .image-cycle-collection__list { 
 z-index: 0; 
 border-radius: 10px; 
 width: 100%; 
 height: 100%; 
 position: absolute; 
 top: 0; 
 left: 0; 
 overflow: hidden; 
 } 
  
 /* Image item positioning */ 
 #unique-image-cycler-widget .image-cycle-collection__img { 
 width: 100%; 
 height: 100%; 
 position: absolute; 
 top: 0; 
 left: 0; 
 object-fit: cover; 
 } 
  
 /* Image inside container */ 
 #unique-image-cycler-widget .image-cycle-collection__img img { 
 width: 100%; 
 height: 100%; 
 object-fit: cover; 
 } 
  
 /* Active image state */ 
 #unique-image-cycler-widget [data-image-cycle-item="active"] { 
 transition: opacity 0.4s ease 0s, visibility 0s ease 0s; 
 opacity: 1; 
 visibility: visible; 
 z-index: 3; 
 } 
  
 /* Previous image state (fading out) */ 
 #unique-image-cycler-widget [data-image-cycle-item="previous"] { 
 transition: opacity 0.4s ease 0.4s, visibility 0s ease 0.4s; 
 opacity: 0; 
 visibility: visible; 
 z-index: 2; 
 } 
  
 /* Inactive image state */ 
 #unique-image-cycler-widget [data-image-cycle-item="not-active"] { 
 opacity: 0; 
 visibility: hidden; 
 z-index: 1; 
 } 
  
 /* Responsive adjustments for mobile */ 
 @media screen and (max-width: 767px) { 
 #unique-image-cycler-widget .image-cycle-collection__list { 
 border-radius: 10px; /* Maintain 10px radius on mobile */ 
 } 
 } 
 </style> 
 <!-- CSS SECTION END --> 
  
 <!-- JAVASCRIPT SECTION START --> 
 <script> 
 // Self-executing function to avoid global scope pollution 
 (function() { 
 // Initialize when DOM is fully loaded 
 document.addEventListener('DOMContentLoaded', function() { 
 initImageCycle(); 
 }); 
  
 /** 
 * Initialize image cycling functionality 
 * Finds all image cycle containers and sets up automatic cycling 
 */ 
 function initImageCycle() { 
 // Find all image cycle containers within our widget 
 const widgetContainer = document.getElementById('unique-image-cycler-widget'); 
 const cycleElements = widgetContainer.querySelectorAll("[data-image-cycle]"); 
  
 cycleElements.forEach(cycleElement => { 
 // Get all items in this cycle group 
 const items = cycleElement.querySelectorAll("[data-image-cycle-item]"); 
  
 // Skip if there aren't enough items to cycle 
 if (items.length < 2) return; 
  
 let currentIndex = 0; 
 let intervalId; 
 const duration = 2000; // Time between transitions in milliseconds 
 const isTwoItems = items.length === 2; 
  
 // Initialize: First item active, others not-active 
 items.forEach((item, i) => { 
 item.setAttribute("data-image-cycle-item", i === 0 ? "active" : "not-active"); 
 }); 
  
 /** 
 * Cycle to the next image in the collection 
 */ 
 function cycleImages() { 
 const prevIndex = currentIndex; 
 currentIndex = (currentIndex + 1) % items.length; 
  
 if (isTwoItems) { 
 // Special case: Only two images - toggle between "previous" and "active" 
 items[prevIndex].setAttribute("data-image-cycle-item", "previous"); 
 } else { 
 // Normal case: Three or more images 
 items[prevIndex].setAttribute("data-image-cycle-item", "previous"); 
  
 // Set to not-active after transition completes 
 setTimeout(() => { 
 items[prevIndex].setAttribute("data-image-cycle-item", "not-active"); 
 }, duration); 
 } 
  
 // Set new active item 
 items[currentIndex].setAttribute("data-image-cycle-item", "active"); 
 } 
  
 // Use IntersectionObserver to start/stop cycling when in/out of viewport 
 const observer = new IntersectionObserver(([entry]) => { 
 if (entry.isIntersecting && !intervalId) { 
 // Start cycling when element is visible 
 intervalId = setInterval(cycleImages, duration); 
 } else if (!entry.isIntersecting && intervalId) { 
 // Stop cycling when element is not visible 
 clearInterval(intervalId); 
 intervalId = null; 
 } 
 }, { threshold: 0 }); 
  
 // Start observing the element 
 observer.observe(cycleElement); 
 }); 
 } 
 })(); 
 </script> 
 <!-- JAVASCRIPT SECTION END --> 
 </div> 

Implementation

The Image Cycling Widget creates a smooth, automated slideshow that transitions between images with elegant fade effects. When in the viewport, the widget automatically cycles through images at a set interval, providing a visually engaging experience while conserving resources when not visible.

HTML Structure

Use the following HTML structure:

  • The main container unique-image-cycler-widget holds all cycling components
  • The image-cycle-collection div creates the proportional container
  • The image-cycle-collection__before element establishes the aspect ratio
  • The image-cycle-collection__list with data-image-cycle attribute contains all images
  • Each image is wrapped in a image-cycle-collection__img div with data-image-cycle-item attribute
CSS Styling

The CSS manages layout, transitions, and state management:

  • Uses absolute positioning for image overlay and smooth transitions
  • Implements three distinct states for images:
    • active : Currently visible image
    • previous : Recently active image transitioning out
    • not-active : All other images not currently in transition
  • Uses object-fit: cover to maintain proper image proportions
  • Controls border radius (10px) for a clean, modern appearance
  • Implements staggered opacity transitions for smooth fading between images
  • Contains responsive adjustments for different screen sizes
JavaScript Functionality

The JavaScript handles cycling logic and viewport detection:

  • Initialization: Sets up image states with first image active
  • Cycling Logic: Manages transitions between images at regular intervals
  • Viewport Detection: Uses IntersectionObserver to detect when the widget is visible
  • Resource Management: Pauses cycling when not in viewport to save resources
  • Special Case Handling: Different behavior for two-image galleries vs. multiple images
  • State Management: Properly applies CSS classes for managing transitions
Customization Tips

You can easily customize various aspects of the widget:

  • Transition Speed: Modify the duration variable (currently 2000ms) to change cycling speed
  • Border Radius: Adjust the border-radius property on .image-cycle-collection__list
  • Aspect Ratio: Change the padding-top percentage on .image-cycle-collection__before
  • Transition Effects: Modify the transition properties for different fade effects
  • Image Count: Add or remove image elements in the HTML structure
  • Container Size: The widget fills 100% of its parent container, so control size by adjusting the parent
CMS Integration

To integrate with a CMS:

  • Create a collection for image items with fields for:
    • Image file (recommend consistent aspect ratios)
    • Alt text for accessibility
    • Optional caption or description
  • Implement a loop in your template to generate each image element
  • Use a unique ID if multiple cyclers appear on one page
  • Adjust the document.getElementById() selector in JavaScript to match your unique ID
  • For optimal performance, use appropriately sized images and enable lazy loading
Video Thumbnail

How to edit code using AI

Resource Details:
Image Cycling Widget creates a responsive, automatic image slideshow with smooth fade transitions. Images cycle through a sequence with elegant opacity animations when in viewport. Features include resource-saving viewport detection, customizable transition timing, responsive design, and browser compatibility. Simple HTML/CSS/JS implementation with adjustable border radius, aspect ratio, and container dimensions. Self-contained code requires no dependencies and works in any HTML environment.

Last Updated:

April 12th 2025

Category:

Image Display

Need Help?

Join Slack

Callum Wells
Callum Wells
i
Creator Credits
We always strive to credit creators as accurately as possible. While similar concepts might appear online, we aim to provide proper and respectful attribution.
A black padlock with a keyhole on a white background.

NO-ACCESS

Only for Desktop Users

This page is only available on desktop.

Please Log in on a desktop to gain access.