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('contentLoadImage', (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('contentAppendImage', (e) => {
const { content, container } = e;
if (content.pictureElement && !content.pictureElement.parentNode) {
e.preventDefault();
container.appendChild(content.pictureElement);
}
});

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 Google Map.

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

lightbox.addFilter('itemData', (itemData, index) => {
const googleMapUrl = itemData.element.dataset.googleMapUrl;
if (googleMapUrl) {
itemData.googleMapUrl = googleMapUrl;
}
return itemData;
});

lightbox.on('contentLoad', (e) => {
const { content } = e;
if (content.type === 'google-map') {
e.preventDefault();

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);

console.log('iframe created');
}
});

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%);
}
<div class="pswp-gallery" id="gallery--google-map-demo">
<a 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" 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" data-pswp-type="google-map" 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/2/img-2500.jpg" data-pswp-width="1669" data-pswp-height="2500" target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/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="1669" data-pswp-height="2500" target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/4/img-200.jpg" alt="">
</a>
<a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-2500.jpg" data-pswp-width="2500" data-pswp-height="1666" target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-200.jpg" alt="">
</a>
</div>

Events demo

import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
import PhotoSwipe from '/photoswipe/photoswipe.esm.js';

const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--content-events-test',
children: 'a',
pswpModule: PhotoSwipe
});


lightbox.on('contentInit', ({ content }) => {
console.log('contentInit', content);
});

lightbox.on('contentLoad', ({ content, isLazy }) => {
console.log('contentLoad', content, isLazy);
});

lightbox.on('contentLoadImage', ({ content, isLazy }) => {
console.log('contentLoadImage', content, isLazy);
});

lightbox.on('loadComplete', ({ content, slide }) => {
console.log('loadComplete', content);
});

lightbox.on('contentResize', ({ content, width, height }) => {
console.log('contentResize', content, width, height);
});

lightbox.on('imageSizeChange', ({ content, width, height, slide }) => {
if (!content) {
debugger;
}
console.log('imageSizeChange', content, width, height, slide, slide.index);
});

lightbox.on('contentLazyLoad', ({ content }) => {
console.log('contentLazyLoad', content);
});

lightbox.on('contentDestroy', ({ content }) => {
console.log('contentDestroy', content);
});

lightbox.on('contentAppend', ({ content }) => {
console.log('contentAppend', content);
});

lightbox.on('contentActivate', ({ content }) => {
console.log('contentActivate', content);
});

lightbox.on('contentDeactivate', ({ content }) => {
console.log('contentDeactivate', content);
});

lightbox.on('contentRemove', ({ content }) => {
console.log('contentRemove', content);
});

lightbox.on('moveMainScroll', () => {
console.log('moveMainScroll')
});

lightbox.on('slideActivate', ({ slide }) => {
console.log('slideActivate')
});

lightbox.init();
<div class="pswp-gallery" id="gallery--content-events-test">
<a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.jpg"
data-pswp-width="1875"
data-pswp-height="2500"
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/2/img-2500.jpg"
data-pswp-width="1669"
data-pswp-height="2500"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/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>
<a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-2500.jpg"
data-pswp-width="2500"
data-pswp-height="1668"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-200.jpg" alt="" />
</a>
<a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-2500.jpg"
data-pswp-width="2500"
data-pswp-height="1667"
target="_blank">
<img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-200.jpg" alt="" />
</a>
</div>