PhotoSwipe is a popular JavaScript image gallery library well-suited for desktops browsers and apps on mobile devices with touchscreens. PhotoSwipe provides a smooth and engaging way to showcase images on the web, especially on mobile devices. Here’s a breakdown of its key functionalities.
- Displays images in a lightbox
-
When you click on an image, it overlays the current page with a zoomed-in view of the image. Easily zoom in and out of images and pan around them. View images in full-screen for an immersive experience
- Supports galleries
-
You can link multiple images together, allowing users to easily browse through a collection.
- Touch-friendly
-
Designed with intuitive touch gestures for navigation (swiping, pinching, etc.). Supports touch gestures like swiping, pinching, and dragging.
- Responsive
-
Adapts to different screen sizes and orientations.
- Customizable
-
Offers various options for customization, such as themes, transitions, and social sharing features.
- Keyboard Navigation
-
Navigate through images using keyboard shortcuts.
- Social Sharing
-
Easily share images on social media platforms.
PhotoSwipe comes with a rich API. The programming interface allows developers to create individual user interfaces (UI) for pagination, navigation and more. Find large number of complex examples on the pages of the UI Initiative project.
The rich API makes PhotoSwipe an excellent choice for web developers, not least for template systems like J1 Template. In the current version of the J1 template (version 2025.x), PhotoSwipe is the default slider and replaces the previously used carousels Owl Carousel, Slickslider, and Masterslider by their implementations based on PhotoSwipeJS.
The PhotoSwipe API documentation pages are based on version v11.2.1 for the current J1 template version 2025.x. The idea of providing this documentation is not to simply copy the original pages as duplicates. For better readability and usability, all pages are restructured and enhanced by code examples or improved description texts. The documentation pages for the J1 Template project will be used for the AI-based chat client (planned for 4th quarter of 2025). The agent will be trained by all available documentation pages of the Template system to give users an easy-to-use source for using the J1 Template to create websites for their needs. All previously used slider resources are available in version 2025.x for backward compatibility but are no longer used for the example pages of the built-in web. |
PhotoSwipe Parameters
List of available PhotoSwipe options (parameters) alphabetically ordered. Find option settings also with the PhotoSwipe Documentation.
allowPanToNext
Boolean, true
. Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
allowPanToNext: false
});
lightbox.init();
arrowKeys
Boolean, true
. Left/right arrow keys for navigation.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
arrowKeys: false
});
lightbox.init();
bgOpacity
Sets the background backdrop opacity. Should be always defined by bgOpacity option and not by CSS RGBA color.
Name | Type | Default | Description | Example |
---|---|---|---|
| number | 0.8 | Sets the background backdrop opacity. Should be always defined by bgOpacity option and not by CSS RGBA color.
|
clickToCloseNonZoomable
Boolean, true
. If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
clickToCloseNonZoomable: false
});
lightbox.init();
closeOnVerticalDrag
Boolean, true
. Vertical drag gesture to close the PhotoSwipe.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
pswpModule: PhotoSwipe,
closeOnVerticalDrag: false
});
lightbox.init();
easing
String, 'cubic-bezier(.4,0,.22,1)'
. CSS easing function for open/close/zoom transitions.
Find an Example here.
escKey
Boolean, true
. Esc key to close.
errorMsg
String, 'The image cannot be loaded'
.
Message to display when the image wasn’t able to load. If you need to display HTML - use contentErrorElement filter.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
errorMsg: 'The photo cannot be loaded'
});
lightbox.init();
getViewportSizeFn
Function {x: width, y: height}
, undefined
. A function that should return slide viewport width and height, in format {x: 100, y: 100}
.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
getViewportSizeFn: function(options, pswp) {
return {
x: document.documentElement.clientWidth - 200,
y: window.innerHeight
};
}
});
lightbox.init();
hideAnimationDuration
Number, 333
.
Transition duration in milliseconds, can be 0
.
Find an Example here.
Use options showAnimationDuration and hideAnimationDuration (Integer, default 333).
Option easing (String, default cubic-bezier(.4,0,.22,1)) accepts any CSS timing-function. It is applied to any zoom transition (including double-tap).
Both options can be modified dynamically while PhotoSwipe is opened.
In the example below transition duration is set to 1000ms (1s). Easing is defined dynamically (opening transition gets ease-out-back, zoom transitions gets ease-in-out-back, and closing transition gets ease-in-back):
const backEasing = {
in: 'cubic-bezier(0.6, -0.28, 0.7, 1)',
out: 'cubic-bezier(0.3, 0, 0.32, 1.275)',
inOut: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
};
const lightbox = new PhotoSwipeLightbox({
gallery:'#gallery_id',
pswpModule: PhotoSwipe,
children:'a',
showHideAnimationType: 'zoom',
showAnimationDuration: 1000,
hideAnimationDuration: 1000
});
lightbox.on('firstUpdate', () => {
lightbox.pswp.options.easing = backEasing.out;
});
lightbox.on('initialZoomInEnd', () => {
lightbox.pswp.options.easing = backEasing.inOut;
});
lightbox.on('close', () => {
lightbox.pswp.options.easing = backEasing.in;
});
lightbox.init();
indexIndicatorSep
String, /
. Used for slide count indicator ("1 of 10 ").
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
indexIndicatorSep: ' of '
});
lightbox.init();
loop
Boolean, true
. If set to true you’ll be able to swipe from the last to the first image. Option is always false
when there are less than 3 slides.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
loop: false
});
lightbox.init();
mainClass
String, undefined
. Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space. Example on Styling page.
appendToEl
DOMElement, document.body
. Element to which PhotoSwipe dialog will be appended when it opens.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
appendToEl: document.querySelector('#__docusaurus')
});
lightbox.init();
maxWidthToAnimate
Integer, 4000
. Maximum width of image to animate, if initial rendered image width is larger than this value - the opening/closing transition will be automatically disabled.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
maxWidthToAnimate: 800,
});
lightbox.init();
padding
Object, { top: 0, bottom: 0, left: 0, right: 0 }
. Slide area padding (in pixels).
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
padding: { top: 20, bottom: 40, left: 100, right: 100 }
});
lightbox.init();
paddingFn
Function, should return padding object. The option is checked frequently, so make sure it’s performant. Overrides padding
option if defined. For example:
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
paddingFn: (viewportSize, itemData, index) => {
return {
// check based on slide index
top: index === 0 ? 100 : 0,
// check based on viewport size
bottom: viewportSize.x < 600 ? 0 : 200,
// check based on image size
left: itemData.w < 2000 ? 50 : 0,
right: 0
};
}
});
lightbox.init();
pinchToClose
Boolean, true
. Pinch touch gesture to close the gallery.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
pinchToClose: false
});
lightbox.init();
preload
Array, [1, 2]
. Lazy loading of nearby slides based on direction of movement. Should be an array with two integers, first one - number of items to preload before the current image, second one - after the current image. Two nearby images are always loaded.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
preload: [1, 4]
});
lightbox.init();
preloaderDelay
Number (ms), 2000
. Delay before the loading indicator will be displayed, if image is loaded during it - the indicator will not be displayed at all. Can be zero.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
preloaderDelay: 0
});
lightbox.init();
returnFocus
Boolean, true
. Restore focus the last active element after PhotoSwipe is closed.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
returnFocus: false
});
lightbox.init();
showAnimationDuration
Number, 333
. Transition duration in milliseconds, can be 0
.
Find an Example here.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
escKey: false
});
lightbox.init();
spacing
Number, 0.1
. Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
spacing: 0.5, // 50% of viewport width
});
lightbox.init();
trapFocus
Boolean, true
. Trap focus within PhotoSwipe element while it’s open.
wheelToZoom
Boolean, undefined
. By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
wheelToZoom: true
});
lightbox.init();
zoomAnimationDuration
Number, 333
. Transition duration in milliseconds, can be 0
.
Find an Example here.
zoomLevel
initialZoomLevel, secondaryZoomLevel, maxZoomLevel
Refer to Adjusting zoom level page for more info. The default values are described there too.
Methods
You can access the PhotoSwipe core instance after the lightbox is opened. For example within the beforeOpen
event.
Alternatively, you may use PhotoSwipe core without Lightbox, see example on Data Sources page.
const lightbox = new PhotoSwipeLightbox({
// options...
});
lightbox.init();
lightbox.on('beforeOpen', () => {
const pswp = lightbox.pswp;
// go to slide by index
pswp.goTo(3);
// go to next slide
pswp.next();
// go to previous slide
pswp.prev();
// close the PhotoSwipe (with animation, if enabled)
// PhotoSwipe will automatically destroy after it's closed
pswp.close();
// instantly close and destroy the PhotoSwipe
pswp.destroy();
// zoom slide to
pswp.currSlide.zoomTo(
1, // slide zoom level, 1 - original image size
{ x: 0, y: 0 }, // zoom center point
2000, // transition duration, can be 0
false // wether pan/zoom bounds should be ignored
);
// pan slide to
pswp.currSlide.panTo(
100, // x position
100, // y position
);
});
Dynamically adding or removing slides
PhotoSwipe parses and renders only nearby slides based on preload
option (but not less than 2 nearby).
The data about slides is stored within pswp.options.dataSource
and its structure depends on the source. If you initialize PhotoSwipe from DOM elements (via gallery
and children
options) the dataSource
will be:
pswp.options.dataSource = {
gallery: '#gallery_id',
items: [
<Child element>,
// ...
<Child element>
]
}
And if you pass an array as a dataSource
, it’ll be kept the same way:
pswp.options.dataSource = [
{ src: 'image1.jpg', width: 100, height: 50 },
// ...
{ src: 'image3.jpg', width: 100, height: 50 }
]
You may modify the pswp.options.dataSource
array however you like, as push new items, replace, sort, pop, shift, etc.
If you’ve modified slides that are currently active (current, next or previous). call method refreshSlideContent(slideIndex)
to reload a slide by index. For example:
const lightbox = new PhotoSwipeLightbox ({
pswpModule: PhotoSwipe,
dataSource: [
{ src: 'https://dummyimage.com/800x600/555/fff/?text=1', width: 800, height: 600 },
// ...
{ src: 'https://dummyimage.com/800x600/555/fff/?text=5', width: 800, height: 600 },
]
});
lightbox.on('uiRegister', () => {
const { pswp } = lightbox;
let replacedCount = 0;
pswp.ui.registerElement({
name: 'replaceCurrentSlide',
className: 'pswp__button--test-button',
order: 9,
isButton: true,
html: 'Replace Current Slide',
onClick: (event, el) => {
replacedCount++;
pswp.options.dataSource[pswp.currSlide.index] = {
src: 'https://dummyimage.com/800x600/555/fff/?text=New%20Slide%20' + replacedCount, width: 800,
height: 600
};
pswp.refreshSlideContent(pswp.currSlide.index);
}
});
let addedCount = 0;
pswp.ui.registerElement({
name: 'addSlide',
className: 'pswp__button--test-button',
order: 9,
isButton: true,
html: 'Add Slide',
onClick: (event, el) => {
addedCount++;
pswp.options.dataSource.push({
src: 'https://dummyimage.com/800x600/555/fff/?text=Added%20slide%20' + addedCount, width: 800,
height: 600
});
pswp.refreshSlideContent(pswp.getNumItems() - 1);
}
});
});
lightbox.init();
document.querySelector('#btn-add-remove-test').onclick = () => {
lightbox.loadAndOpen(0);
};
PhotoSwipe Lightbox
PhotoSwipe is a popular JavaScript library designed to create engaging and interactive image galleries. It is often called a lightbox because when you click on an image, it opens in a new, overlaying layer, darkening the background and focusing the image.
See PhotoSwipe Documentation. and PhotoSwipeLightbox Methods for examples.
Name | Description |
---|---|
| Element, NodeList, or CSS selector (string) for the gallery element, a swiper slider for example. |
| Element, NodeList, or CSS selector (string) for elements within a |
pswpModule
Function or Module. Should return import(), if you need to dynamic import.
Default: undefined
pswpModule: PhotoSwipe
Or the PhotoSwipe Core module itself.
const lightbox = new PhotoSwipeLightbox({
pswpModule: PhotoSwipe
// ...
});
preloadFirstSlide
Boolean, true
. Loads the first slide image in parallel with PhotoSwipe Core (while PhotoSwipe is opening).
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
preloadFirstSlide: false
});
lightbox.init();
Translating
A list of options that might need a translation.
{
closeTitle: 'Close',
zoomTitle: 'Zoom',
arrowPrevTitle: 'Previous',
arrowNextTitle: 'Next',
errorMsg: 'The image cannot be loaded',
indexIndicatorSep: '/'
}
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
closeTitle: 'Close the dialog',
zoomTitle: 'Zoom the photo',
arrowPrevTitle: 'Go to the previous photo',
arrowNextTitle: 'Go to the next photo',
errorMsg: 'The photo cannot be loaded',
indexIndicatorSep: ' of ',
preloadFirstSlide: false
});
lightbox.init();
Methods
init
init()
Initialize the lightbox, must be called once for each instance. It does not open the dialog, only binds events that would open it (by default just click
). It also allows preloading images before the dialog is opened.
const lightbox = new PhotoSwipeLightbox({
// options
});
// you may bind events here
lightbox.init();
destroy
destroy()
Unbinds all events, and closes PhotoSwipe if it is currently open. Once the instance is destroyed, it cannot be initialized again.
let lightbox = new PhotoSwipeLightbox ({
gallery: '#gallery--test-destroy',
pswpModule: PhotoSwipe,
children: 'a',
returnFocus: false
});
lightbox.init();
const button = document.createElement('button');
button.type = 'button';
button.innerText = 'destroy the photoswipe';
document.querySelector('#gallery--test-destroy').after(button);
button.onclick = () => {
if (lightbox) {
lightbox.destroy();
lightbox = null;
}
}
loadAndOpen
loadAndOpen(index, dataSource, point)
Open PhotoSwipe at a given index. Arguments:
-
Index of a slide to open (
number
) -
Optional data source (
DataSource
). -
Optional
Point
(x: number, y: number
) that determines where exactly the user clicked on the thumbnail. Bby default it is{ x: e.clientX, y: e.clientY }
of the correspondingclick
event).
If you use gallery
& children
options and you omit the second argument (do not provide data source) - PhotoSwipe will use the first gallery
element. To select another gallery
element you must define data source as { gallery: HTMLElement }
, for example:
const lightbox = new PhotoSwipeLightbox ({
gallery: '#gallery--with-button',
pswpModule: PhotoSwipe,
children: 'a',
});
lightbox.init();
const btn = document.createElement ('button');
btn.type = 'button';
btn.innerText = 'open second image';
document.querySelector('#gallery--with-button').after(btn);
btn.onclick = () => {
lightbox.loadAndOpen(1, {
gallery: document.querySelector ('#gallery--with-button')
});
// You also can just trigger the native click
// document.querySelector('#gallery--with-button a:nth-of-type(2)').click();
};
Events
All events can be bound directly to lightbox, they’ll automatically map to PhotoSwipe core when it’s open.
const lightbox = new PhotoSwipeLightbox({
// options...
});
lightbox.init();
Initialization
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-init-events',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.on('beforeOpen', () => {
console.log('beforeOpen');
// photoswipe starts to open
});
lightbox.on('firstUpdate', () => {
console.log('firstUpdate');
// photoswipe keeps opening
// you may modify initial index or basic DOM structure
});
lightbox.on('initialLayout', () => {
console.log('initialLayout');
// photoswipe measures size of various elements
// if you need to read getBoundingClientRect of something - do it here
});
lightbox.on('change', () => {
// triggers when slide is switched, and at initialization
console.log('change');
});
lightbox.on('afterInit', () => {
console.log('afterInit');
// photoswipe fully initialized and opening transition is running (if available)
});
lightbox.on('bindEvents', () => {
console.log('bindEvents');
// photoswipe binds DOM events (such as pointer events, wheel, etc)
});
lightbox.init();
Opening or Closing transitions
The events will trigger even if transition is disabled.
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-opening-closing-events',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.on('openingAnimationStart', () => {
console.log('openingAnimationStart');
});
lightbox.on('openingAnimationEnd', () => {
console.log('openingAnimationEnd');
});
lightbox.on('closingAnimationStart', () => {
console.log('closingAnimationStart');
});
lightbox.on('closingAnimationEnd', () => {
console.log('closingAnimationEnd');
});
lightbox.init();
Closing
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-closing-events',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.on('close', () => {
// PhotoSwipe starts to close, unbind most events here
console.log('close');
});
lightbox.on('destroy', () => {
// PhotoSwipe is fully closed, destroy everything
console.log('destroy');
});
lightbox.init();
Pointer and Gesture
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-pointer-events',
children: 'a',
pswpModule: () => import('/photoswipe/photoswipe.esm.js')
});
lightbox.on('pointerDown', (e) => {
console.log('pointerDown', e.originalEvent);
});
lightbox.on('pointerMove', (e) => {
console.log('pointerMove', e.originalEvent);
});
lightbox.on('pointerUp', (e) => {
console.log('pointerUp', e.originalEvent);
});
lightbox.on('pinchClose', (e) => {
// triggered when using pinch to close gesture
// can be default prevented
console.log('pinchClose', e.bgOpacity);
});
lightbox.on('verticalDrag', (e) => {
// triggered when using vertical drag to close gesture
// can be default prevented
console.log('verticalDrag', e.panY);
});
lightbox.init();
Slide content
Refer to Custom Content section of docs for examples.
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
import PhotoSwipe from '/photoswipe/photoswipe.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-content-events',
children: 'a',
pswpModule: PhotoSwipe
});
lightbox.on('contentInit', ({ content }) => {
console.log('contentInit', content);
});
lightbox.on('contentLoad', ({ content, isLazy }) => {
// content starts to load
// can be default prevented
// assign elements to `content.element`
console.log('contentLoad', content, isLazy);
});
lightbox.on('contentLoadImage', ({ content, isLazy }) => {
// similar to the previous one, but triggers only for image content
// can be default prevented
console.log('contentLoadImage', content, isLazy);
});
lightbox.on('loadComplete', ({ content, slide }) => {
console.log('loadComplete', content);
});
lightbox.on('contentResize', ({ content, width, height }) => {
// content will be resized
// can be default prevented
console.log('contentResize', content, width, height);
});
lightbox.on('imageSizeChange', ({ content, width, height, slide }) => {
// content.element is image
console.log('imageSizeChange', content, width, height, slide, slide.index);
});
lightbox.on('contentLazyLoad', ({ content }) => {
// content start to lazy-load
// can be default prevented
console.log('contentLazyLoad', content);
});
lightbox.on('contentAppend', ({ content }) => {
// content is added to dom
// can be default prevented
// content.slide.container.appendChild(content.element);
console.log('contentAppend', content);
});
lightbox.on('contentActivate', ({ content }) => {
// content becomes active (the current slide)
// can be default prevented
console.log('contentActivate', content);
});
lightbox.on('contentDeactivate', ({ content }) => {
// content becomes inactive
// can be default prevented
console.log('contentDeactivate', content);
});
lightbox.on('contentRemove', ({ content }) => {
// content is removed from DOM
// can be default prevented
console.log('contentRemove', content);
});
lightbox.on('contentDestroy', ({ content }) => {
// content will be destroyed
// can be default prevented
console.log('contentDestroy', content);
});
lightbox.init();
Lightbox Captions
PhotoSwipe does not support captions out of the box, but a plugin is available. The plugin can automatically position the text below or aside the image, depending on the available space for small to medium-sized captions and only for images with the default fit
scale mode.
For accessibility, make sure that important captions are always available without PhotoSwipe - either use an alt
attribute on thumbnails or aria-labelledby
.
Initialization
The plugin has a single JS file photoswipe-caption-plugin.min.js and a single CSS file photoswipe-caption-plugin.css. The plugin can be initialized like so:
Base HTML Layout v1
Nihil voluptatem impedit officia voluptatem architecto voluptas nesciunt consequatur ea cupiditate aliquam exercitationem autem. Rerum eum exercitationem velit non praesentium voluptatum eaque voluptatem id ut. Et quo accusamus at quod id.
<!-- Slider main container (required) -->
<div id="gallery_id" class="swiper swiper-container">
<!-- Slider wrapper element (required) -->
<div class="swiper-wrapper">
<!-- Slides (required) -->
<div class="swiper-slide">
<img src="path/to/image-1.jpg">
<span class="pswp-caption-content">Caption: Image 1</span>
</div>
<!-- more slides -->
<div class="swiper-slide">
<img src="path/to/image-x.jpg">
<span class="pswp-caption-content">Caption: Image X</span>
</div>
</div> <!-- END wrapper element -->
<!-- Sniper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Sniper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Sniper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->
Base HTML Layout v2
Optio expedita perspiciatis dignissimos quia qui debitis autem explicabo provident. Quis consequatur veniam reprehenderit aut non ab voluptatem rerum in dolor. Tempore quasi delectus expedita aut sit et nesciunt molestiae dolores amet earum quae.
<!-- Slider main container (required) -->
<div id="gallery_id" class="swiper swiper-container">
<!-- Slider wrapper element (required) -->
<ul class="swiper-wrapper">
<!-- Slides (required) -->
<li class="swiper-slide">
<img src="path/to/image-1.jpg">
<span class="pswp-caption-content">Caption: Image 1</span>
</li>
<!-- more slides -->
<li class="swiper-slide">
<img src="path/to/image-x.jpg">
<span class="pswp-caption-content">Caption: Image X</span>
</li>
</ul> <!-- END swiper-wrapper (slides) -->
<!-- Sniper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Sniper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Sniper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->
Extended HTML Layout
Est voluptas ipsum adipisci voluptas. Ex aperiam dolores culpa sit dolorum et non corrupti necessitatibus. Accusamus animi mollitia officiis distinctio nisi et sit veniam.
<!-- Slider main container (required) -->
<div id="gallery_id" class="swiper swiper-container">
<!-- Slider wrapper element (required) -->
<ul class="swiper-wrapper">
<!-- Slides (required) -->
<li class="swiper-slide">
<a href="path/to/image-1.jpg"
data-pswp-width="<max_width>"
data-pswp-height="<max_height>">
<img src="path/to/image-1.jpg" alt="Image 1">
<span class="pswp-caption-content">Caption: Image 1</span>
</a>
</li>
<!-- more slides -->
<li class="swiper-slide">
<a href="path/to/image-x.jpg"
data-pswp-width="<max_width>"
data-pswp-height="<max_height>">
<img src="path/to/image-x.jpg" alt="Image X">
<span class="pswp-caption-content">Caption: Image X</span>
</a>
</li>
</ul> <!-- END swiper-wrapper (slides) -->
<!-- Sniper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Sniper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Sniper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->
Sniper Initialization (Javascript)
Nihil magni vel pariatur et et sit ea autem debitis explicabo omnis sequi. Et distinctio odio est architecto occaecati et ipsam velit ea veritatis qui. Deserunt quos eos ullam perferendis sit aperiam aliquam quia rerum mollitia tempora et ullam.
<!-- Sniper Initialization (Javascript) -->
<script>
const myLightbox = new PhotoSwipeLightbox({
gallerySelector: '#my_gallery',
pswpModule: PhotoSwipe,
// .. other options
});
const captionPlugin = new PhotoSwipeDynamicCaption(myLightbox, {
type: 'auto'
});
// init photoswipe core >>after<< the plugin is added
myLightbox.init();
</script>
PhotoSwipe Caption Parameters
Fuga ut quam illum placeat nisi molestias consequuntur ut beatae. Eum accusantium rerum eum recusandae in. Qui vel qui aut voluptatibus ut labore non saepe architecto.
Name | Type | Default | Description | Example |
---|---|---|---|
| string | .pswp-caption-content | Used to retrieve caption content. Can be a selector of the element from which caption content will be retrieved, if the element is not found, the plugin will try to use the thumbnail image |
| string | auto | Position type of the caption can be auto, below, or aside.
|
| number | 600 | Maximum window width at which mobile layout should be used, or a function that should return true if mobile layout should be used. Example
|
| number | 20 | When the caption |
| number | 0.3 | Ratio defines the amount of horizontal empty space before the mobile caption switches to an “overlap” layout. For example, if it’s set to 0.3 - the caption will start overlapping the image when more than 30% of horizontal space is not occupied by an image. If you set it to 0 - the caption will always overlap. If you set it to 1 - the caption will constantly shift the image (unless it’s taller than the viewport). |
| boolean |
| If enabled, the image will always be vertically centered in the remaining space between the caption and the rest of the viewport. If set to false (default value) - the image will lift up only if the caption does not fit below. |
Styling
The caption has class pswp__dynamic-caption
.
It can be in one of these states:
-
Below the main image -
pswp__dynamic-caption—below
. -
Right side of the main image -
pswp__dynamic-caption—aside
. -
“Mobile” (by default just pinned to bottom) -
pswp__dynamic-caption—mobile
If the caption is near the left horizontal edge - it gets class pswp__dynamic-caption—on-hor-edge
.
Feel free to adjust styles in the plugin CSS file (and use media queries if you need to):
.pswp__dynamic-caption--aside {
max-width: 300px;
padding: 20px 15px 20px 20px;
margin-top: 70px;
}
.pswp__dynamic-caption--below {
max-width: 700px;
padding: 15px 0 0;
}
.pswp__dynamic-caption--mobile {
background: rgba(0, 0, 0, 0.5);
padding: 10px 15px;
}
How auto positioning works
-
Check if there is more horizontal or vertical free space around the image.
-
If there is more free vertical space:
-
Set caption width to the width of the image
-
Add
pswp__dynamic-caption—below
class, so the size can also be adjusted via CSS. -
Measure caption height.
-
Check if the caption will fit without any adjustments to the image position.
-
If it does - just show the caption below the image.
-
If it doesn’t - reduce the pan area height by the height of the caption.
-
-
-
If there is more horizontal space:
-
Add
pswp__dynamic-caption—aside
class, so the size can be adjusted via CSS. -
Measure caption width.
-
Check if caption will fit on the right side without any adjustments of image position.
-
If it does - just show the caption aside from the image.
-
If it doesn’t - reduce the pan area width by the width of the caption.
-
-
If mobileLayoutBreakpoint
requirements are met:
-
Measure caption height when it occupies 100% of width.
-
Reduce pan area height to fit the caption below the image.
-
Check the amount of free horizontal space after the adjustment.
-
If there is too much horizontal space (
mobileCaptionOverlapRatio
), just overlap the caption and keep the image at the default position.