Skip to main content

Custom Content in Slides

By default PhotoSwipe can only show images or raw HTML content, but you may use content events and filters to support new types.

Please note that PhotoSwipe is mainly designed to display photos. There are issues with displaying other types of content - for example, you can't swipe over iframes. Always have a fallback, for example if you embed Google Map - make sure that there is an outbound link to it.

Using WebP image format

The example below uses <picture> instead of <img> for slides that support webp. The webp image source is retrieved from data-pswp-webp-src attribute.

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--webp-demo',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});

// Parse data-pswp-webp-src attribute
lightbox.addFilter('itemData', (itemData, index) => {
const webpSrc = itemData.element.dataset.pswpWebpSrc;
if (webpSrc) {
itemData.webpSrc = webpSrc;
}
return itemData;
});

// use <picture> instead of <img>
lightbox.on('contentLoad', (e) => {
const { content, isLazy } = e;

if (content.data.webpSrc) {
// prevent to stop the default behavior
e.preventDefault();

content.pictureElement = document.createElement('picture');

const sourceWebp = document.createElement('source');
sourceWebp.srcset = content.data.webpSrc;
sourceWebp.type = 'image/webp';

const sourceJpg = document.createElement('source');
sourceJpg.srcset = content.data.src;
sourceJpg.type = 'image/jpeg';

content.element = document.createElement('img');
content.element.src = content.data.src;
content.element.setAttribute('alt', '');
content.element.className = 'pswp__img';

content.pictureElement.appendChild(sourceWebp);
content.pictureElement.appendChild(sourceJpg);
content.pictureElement.appendChild(content.element);

content.state = 'loading';

if (content.element.complete) {
content.onLoaded();
} else {
content.element.onload = () => {
content.onLoaded();
};

content.element.onerror = () => {
content.onError();
};
}
}
});


// by default PhotoSwipe appends <img>,
// but we want to append <picture>
lightbox.on('contentAppend', (e) => {
const { content } = e;
if (content.pictureElement && !content.pictureElement.parentNode) {
e.preventDefault();
content.slide.container.appendChild(content.pictureElement);
}
});

// for next/prev navigation with <picture>
// by default PhotoSwipe removes <img>,
// but we want to remove <picture>
lightbox.on('contentRemove', (e) => {
const { content } = e;
if (content.pictureElement && content.pictureElement.parentNode) {
e.preventDefault();
content.pictureElement.remove();
}
});

lightbox.init();
<div class="pswp-gallery" id="gallery--webp-demo">
<a
href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.jpg"
data-pswp-width="1875"
data-pswp-height="2500"
data-pswp-webp-src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.webp"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-200.jpg" alt="" />
</a>

<a
href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-2500.jpg"
data-pswp-width="2500"
data-pswp-height="1666"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-200.jpg" alt="" />
</a>

<a
href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/4/img-2500.jpg"
data-pswp-width="2500"
data-pswp-height="1667"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/4/img-200.jpg" alt="" />
</a>

</div>

Google Maps demo

Another example that shows a map <iframe>.

To define the type of slide, you may use data-pswp-type attribute (or type property of the slide object). Built-in types are image and html. The example below uses a custom google-map type.

<a data-pswp-type="google-map" data-google-map-url="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d325518.68780316407!2d30.252511957059642!3d50.4016990487754!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x40d4cf4ee15a4505%3A0x764931d2170146fe!2z0JrQuNC10LIsIDAyMDAw!5e0!3m2!1sru!2sua!4v1647422169265!5m2!1sru!2sua" href="https://maps.google.com/maps?ll=50.402036,30.532691&z=10&t=m&mapclient=embed&q=%D0%9A%D0%B8%D0%B5%D0%B2%2002000" target="_blank"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/map-thumb.png" alt=""></a>
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--google-map-demo',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});

// parse data-google-map-url attribute
lightbox.addFilter('itemData', (itemData, index) => {
const googleMapUrl = itemData.element.dataset.googleMapUrl;
if (googleMapUrl) {
itemData.googleMapUrl = googleMapUrl;
}
return itemData;
});

// override slide content
lightbox.on('contentLoad', (e) => {
const { content } = e;
if (content.type === 'google-map') {
// prevent the deafult behavior
e.preventDefault();

// Create a container for iframe
// and assign it to the `content.element` property
content.element = document.createElement('div');
content.element.className = 'pswp__google-map-container';

const iframe = document.createElement('iframe');
iframe.setAttribute('allowfullscreen', '');
iframe.src = content.data.googleMapUrl;
content.element.appendChild(iframe);
}
});

lightbox.init();
.pswp__google-map-container {
position: relative;
width: 100%;
height: 100%;
pointer-events: none;
}
.pswp__google-map-container iframe {
background: #444;
width: 100%;
height: 100%;
max-width: 800px;
max-height: 600px;
pointer-events: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}