Webflow Rich Text Lightbox

Example:

"The boy continued to listen to his heart as they crossed the desert. He came to understand its dodges and tricks, and to accept it as it was. He lost his fear, and forgot about his need to go back to the oasis, because, one afternoon, his heart told him that it was happy.

Here's a Caption

'Even though I complain sometimes,' it said, 'it's because I'm the heart of a person and people's hearts are that way. People are afraid to pursue their most important dreams, because they feel that they don't deserve them, or that they'll be unable to achieve them. We, their hearts, become fearful just thinking of loved ones who go away forever, or of the moments that could have been good but weren't, or of treasures that might have been found but were forever hidden in the sands. Because, when these things happen, we suffer terribly." - The Alchemist

Code

Copy this code and paste into </body> of your page

<script>
 (() => {
    function replaceImagesWithLightboxes(element) {
      const figures = element.querySelectorAll("figure.w-richtext-figure-type-image");

      figures.forEach((figure) => {
        const imageContainer = figure.querySelector("div");
        const image = imageContainer.querySelector("img");
        if (!image) return; // Skip if no image found

        const imageUrl = image.getAttribute("src");
        const imageAlt = image.getAttribute("alt") || '';
        const imageWidth = image.naturalWidth || image.width;

        // Extract the caption
        const caption = figure.querySelector("figcaption");
        const captionText = caption ? caption.innerText : "";

        // Create lightbox HTML
        const lightbox = document.createElement("a");
        lightbox.setAttribute("href", imageUrl);
        lightbox.classList.add("w-inline-block", "w-lightbox");

        const lightboxImage = document.createElement("img");
        lightboxImage.setAttribute("src", imageUrl);
        lightboxImage.setAttribute("loading", "lazy");
        lightboxImage.setAttribute("sizes", "100vw");
        lightboxImage.setAttribute("srcset", generateSrcset(imageUrl, imageWidth));
        lightboxImage.setAttribute("alt", imageAlt);

        const script = document.createElement("script");
        script.setAttribute("type", "application/json");
        script.classList.add("w-json");
        script.textContent = JSON.stringify({
          items: [
            {
              _id: Math.random().toString(),
              origFileName: imageAlt,
              fileName: imageAlt,
              url: imageUrl,
              width: imageWidth,
              type: "image",
              caption: captionText, // Include the caption text
            },
          ],
          group: "",
        });

        lightbox.appendChild(lightboxImage);
        lightbox.appendChild(script);

        // Clear the existing image container and append the lightbox
        imageContainer.innerHTML = "";
        imageContainer.appendChild(lightbox);

        // If the caption exists, move it outside the figure (as figure is being cleared)
        if (caption) {
          figure.parentNode.insertBefore(caption, figure.nextSibling);
        }

        // Clear the figure but not the caption
        figure.innerHTML = "";
        figure.appendChild(imageContainer);
        if (caption) {
          figure.appendChild(caption);
        }
      });
    }

    function generateSrcset(imageUrl, imageWidth) {
      const sizes = [500, 800, 1080, 1600, 2000];
      return sizes
        .filter(size => size <= imageWidth)
        .map(size => `${imageUrl.replace(".jpg", `-p-${size}.jpg`)} ${size}w`)
        .join(", ") + `, ${imageUrl} ${imageWidth}w`;
    }

    const containerElement = document.querySelector('.text-rich-text.w-richtext');
    if (containerElement) {
      replaceImagesWithLightboxes(containerElement);
    }
  })();
</script>

How it works

1. Defining the replaceImagesWithLightboxes Function: This function is called with an element (in your case, the container of your rich text content). It's responsible for the main functionality of the script.

<script>
 function replaceImagesWithLightboxes(element) {
  const figures = element.querySelectorAll("figure.w-richtext-figure-type-image");
  ...
}
</script>

Here, figures will hold a NodeList of all figure elements within your richtext that have the class w-richtext-figure-type-image.

2. Iterating Over Figures: The script iterates over each figure element found in the previous step. For each figure, it processes the image and its associated caption.

<script>
figures.forEach((figure) => {
  ...
});

</script>

3. Processing Each Image and Caption:

  • Finding the Image and Caption: The script looks for an img tag within a div and a figcaption inside the figure. It extracts the necessary attributes from the image and the text from the caption.
<script>
 const imageContainer = figure.querySelector("div");
const image = imageContainer.querySelector("img");
const caption = figure.querySelector("figcaption");
...

</script>

Skip if No Image Found: If an image isn't found within the figure, the script skips to the next figure.

4. Creating the Lightbox:

  • Lightbox Link: A new <a> element is created, which will act as the lightbox. It's set to open the image URL and is styled with Webflow's lightbox classes.
  • Lightbox Image: A new <img> element is created for the lightbox, with attributes like src, alt, and srcset (for responsive images).
  • Lightbox Script: A <script> tag of type application/json is created. This contains the data for the lightbox, including the image URL, width, and the caption text.

5. Updating the HTML Structure:

  • Clearing and Appending to Image Container: The script clears the imageContainer and appends the newly created lightbox to it.
  • Preserving the Caption: If a caption is present, it is moved to immediately follow the figure element. This is crucial because the script then clears the entire figure element and re-adds the imageContainer (now with the lightbox) and the figcaption.
<script>
 imageContainer.innerHTML = "";
imageContainer.appendChild(lightbox);
...
figure.innerHTML = "";
figure.appendChild(imageContainer);
if (caption) {
  figure.appendChild(caption);
}

</script>

6. Generate Srcset Function: This function creates a srcset attribute value for the lightbox images, enabling responsive image loading based on screen size.

7. Initializing the Script for the Container Element: Finally, the script looks for the container element (.text-rich-text.w-richtext) and calls replaceImagesWithLightboxes on it if the element is found.

<
script>
const containerElement = document.querySelector('.text-rich-text.w-richtext');
if (containerElement) {
  replaceImagesWithLightboxes(containerElement);
}

</script>

In summary, the script finds each image in your richtext, wraps it in a lightbox, and ensures that the captions are preserved and displayed correctly. The figure elements are modified to include this new lightbox functionality while keeping their associated captions in place.