A lightbox is a helper which displays enlarged, almost screen-filling versions of images while dimming the remainder of the page. The technique, introduced by Lightbox Version 2, gained widespread popularity thanks to its simple style. The term lightbox has been employed since then for Javascript libraries to support such functionality.
PhotoSwipe Lightbox is a JavaScript library to create lightboxes placed on images in webpages. When you click such extended images, they open in a new, overlaying layer, darkening the background and focusing the image. Well-suited for desktops, browsers, and apps on mobile devices with touchscreens. The library 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 a 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 PhotoSwipe.
| The PhotoSwipe API documentation pages are based on PhotoSwipe version v5.4.4 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. |
Usage
See PhotoSwipe Documentation and PhotoSwipe Lightbox Methods for more examples.
| Name | Description |
|---|---|
| The gallery element. May be a DOM element, a NodeList, or a CSS selector string. The gallery is the container that holds all the slides – for example a Swiper slider container. |
| The clickable elements inside a gallery. May be a DOM element, a NodeList, or a CSS selector string. Typically this is |
Initialization
A complete PhotoSwipe Lightbox setup needs the lightbox JavaScript file (photoswipe-lightbox.min.js) and the PhotoSwipe core file (photoswipe.min.js), plus the main stylesheet (photoswipe.css). If you also want captions, add the Dynamic Caption plugin (photoswipe-caption-plugin.min.js) and its stylesheet (photoswipe-caption-plugin.css).
The lightbox – with the optional caption plugin attached – is then initialised like so:
<!-- Lightbox initialisation (JavaScript) -->
<script>
const myLightbox = new PhotoSwipeLightbox({
gallery: '#my_gallery',
children: 'a',
pswpModule: PhotoSwipe,
// ... other options
});
// Attach the caption plugin BEFORE myLightbox.init() is called.
const captionPlugin = new PhotoSwipeDynamicCaption(myLightbox, {
type: 'auto'
});
// Initialise the lightbox AFTER all plugins are attached.
myLightbox.init();
</script>Base HTML pattern
HTML pattern (mirrors PhotoSwipe’s standard markup):
<div
data-photoswipe-lightbox="my-gallery">
<a
href="big-1.jpg"
data-pswp-width="1600" data-pswp-height="1067">
<img
src="thumb-1.jpg"
alt="">
</a>
<a
href="big-2.jpg" data-pswp-width="1600"
data-pswp-height="1067">
<img
src="thumb-2.jpg"
alt="">
</a>
</div>HTML pattern v1
The simplest way to combine PhotoSwipe with the Swiper slider is to put a <div> for every slide inside the slider’s wrapper element. Each slide contains the image and (optionally) a hidden caption element.
<!-- 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 -->
<!-- Swiper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Swiper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Swiper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->HTML pattern v2
This variant uses an unordered list (<ul>/<li>) instead of plain <div> elements for the slides. Functionally it is identical to v1; use whichever markup fits your site best.
<!-- 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) -->
<!-- Swiper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Swiper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Swiper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->Extended HTML pattern
The extended layout wraps each thumbnail image in an <a> tag that links to the full-size image. The link also carries data-pswp-width and data-pswp-height attributes so PhotoSwipe knows the natural size of the full image before loading it. This avoids visible layout jumps and is required for the opening animation to work smoothly.
<!-- 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) -->
<!-- Swiper Pagination (optional) -->
<div class="swiper-pagination"></div>
<!-- Swiper Navigation (optional) -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- Swiper Scrollbar (optional)-->
<div class="swiper-scrollbar"></div>
</div> <!-- END Main container -->Preload first slide
Boolean option preloadFirstSlide, default true. When enabled, PhotoSwipe starts downloading the image of the first slide in parallel with the opening animation. This makes the opening feel faster because the image is often ready by the time the animation finishes. Set the option to false if you would rather start the download only after the dialog is fully open.
import PhotoSwipeLightbox from '/photoswipe/photoswipe-lightbox.esm.js';
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
preloadFirstSlide: false
});
lightbox.init();Translating
PhotoSwipe shows a few short pieces of text in its user interface (button tooltips, error messages and the slide-counter separator). You can translate them into any language by overriding the options listed below.
{
closeTitle: 'Close', // tooltip on the close button
zoomTitle: 'Zoom', // tooltip on the zoom button
arrowPrevTitle: 'Previous', // tooltip on the previous-arrow button
arrowNextTitle: 'Next', // tooltip on the next-arrow button
errorMsg: 'The image cannot be loaded',
indexIndicatorSep: '/' // separator in "1 / 10"
}const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
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();Auto initialization
Adds Lightbox V3-style auto-initialization to PhotoSwipeLightbox so that any element matching the configurable selector (default [data-photoswipe-lightbox]) is treated as a gallery container without requiring callers to instantiate new PhotoSwipeLightbox(…) and .init() themselves.
Example
HTML pattern
<div
data-photoswipe-lightbox="auto-gallery">
<a
href="big-1.jpg"
data-pswp-width="1600" data-pswp-height="1067">
<img
src="thumb-1.jpg"
alt="caption text 1">
</a>
<a
href="big-2.jpg"
data-pswp-width="1600" data-pswp-height="1067">
<img
src="thumb-2.jpg"
alt="caption text 2">
</a>
</div>The element carrying data-photoswipe-lightbox (auto-gallery) is the gallery. Its descendant <a> tags are the slides. The attribute value is treated purely as a logical id (useful for getAutoInitInstance lookups) and is not required.
Parameters
A list of all available options (parameters) in alphabetical order. You can also find the original option settings in 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. Use the left and right arrow keys to move between slides.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
arrowKeys: false
});
lightbox.init();bgOpacity
Number, 0.8. Sets how transparent the dark backdrop behind the image is. A value of 0 is fully transparent, 1 is fully opaque. The backdrop’s color is set in CSS via --pswp-bg; only its opacity should be set here.
| Name | Type | Default | Description | Example |
|---|---|---|---|
| number | 0.8 | Controls how transparent the backdrop behind the image is. |
clickAction
Configures what happens when the user clicks on the image (imageClickAction) or on the dark background around it (bgClickAction). Possible values include 'close', 'next', 'zoom', 'zoom-or-close' and false (no action).
Refer to the click and tap actions page for the full list and examples.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
imageClickAction: 'zoom-or-close',
bgClickAction: 'close'
});
lightbox.init();clickToCloseNonZoomable
Boolean, true. If an image cannot be zoomed (for example, because it is smaller than the viewport), clicking on it will close the lightbox.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
clickToCloseNonZoomable: false
});
lightbox.init();closeOnVerticalDrag
Boolean, true. Close the lightbox by dragging the image up or down (touch devices).
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
closeOnVerticalDrag: false
});
lightbox.init();easing
String, 'cubic-bezier(.4,0,.22,1)'. Sets the CSS easing function used for the open, close and zoom transitions. Any valid CSS transition-timing-function value is accepted.
Find an Example here.
escKey
Boolean, true. Allow the user to close the lightbox by pressing the Esc key.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
escKey: false
});
lightbox.init();errorMsg
String, 'The image cannot be loaded'.
The text that is shown when an image fails to load. If you need to display formatted HTML instead of plain text, use the contentErrorElement filter.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
errorMsg: 'The photo cannot be loaded'
});
lightbox.init();getViewportSizeFn
Function, undefined. A function that returns the size of the slide’s viewport in pixels. The function receives the merged options object and the PhotoSwipe instance and must return an object of the form { x: <width>, y: <height> }. Use this when the lightbox is rendered inside a container that is smaller than the browser window.
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. Closing transition duration in milliseconds. Set to 0 to disable the closing animation.
Find an Example here.
You can use the options showAnimationDuration and hideAnimationDuration together (both are integers, default 333).
The easing option (string, default cubic-bezier(.4,0,.22,1)) accepts any CSS timing function and applies to every zoom transition (including double-tap).
Both options can also be changed dynamically while PhotoSwipe is open.
In the example below the transition duration is set to 1000 ms (1 s). The easing is changed dynamically: the opening transition uses ease-out-back, the zoom transitions use ease-in-out-back and the closing transition uses 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, ' / '. The separator used by the slide counter in the top toolbar. The default produces strings like 1 / 10. Use ' of ' to get 1 of 10 instead.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
indexIndicatorSep: ' of '
});
lightbox.init();loop
Boolean, true. When enabled, swiping past the last slide takes the user back to the first slide (and vice versa). The option is always treated as false when the gallery has fewer than three slides.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
loop: false
});
lightbox.init();mainClass
String, undefined. One or more CSS class names (separated by a space) that are added to the root element of PhotoSwipe. Use this to apply custom styles to a single lightbox instance. An example can be found on the Styling page.
appendToEl
DOM element, document.body. The element that PhotoSwipe will be appended to when it opens. Useful when the page uses a custom layout container (for example a documentation framework) that should host the lightbox instead of <body>.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
appendToEl: document.querySelector('#__docusaurus')
});
lightbox.init();maxWidthToAnimate
Integer, 4000. Maximum width (in pixels) of an image that should be animated when opening or closing the lightbox. If the rendered image is wider than this value, the open/close animation is automatically disabled to keep the transition smooth.
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 }. Adds inner padding (in pixels) around the slide area on each side. Useful for keeping content (such as captions or toolbars) away from the edges of the viewport.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
padding: { top: 20, bottom: 40, left: 100, right: 100 }
});
lightbox.init();paddingFn
Function, undefined. A function that returns a padding object (same shape as padding). Overrides the padding option when set. The function is called frequently, so keep it simple and fast. The function receives the current viewport size, the data of the current slide and the slide index.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
paddingFn: (viewportSize, itemData, index) => {
return {
// value depends on the slide index
top: index === 0 ? 100 : 0,
// value depends on the viewport size
bottom: viewportSize.x < 600 ? 0 : 200,
// value depends on the image size
left: itemData.w < 2000 ? 50 : 0,
right: 0
};
}
});
lightbox.init();pinchToClose
Boolean, true. Allow the user to close the lightbox with a pinch-out touch gesture.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
pinchToClose: false
});
lightbox.init();preload
Array, [1, 2]. Preload nearby slides based on the user’s direction of movement. The first number is how many images to preload before the current one, the second is how many to preload after it. The two neighbouring 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 (in milliseconds) before the spinning loading indicator appears. If the image finishes loading before this delay is up, the indicator never shows. Use 0 to display the indicator immediately.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
preloaderDelay: 0
});
lightbox.init();returnFocus
Boolean, true. After the lightbox is closed, move the keyboard focus back to the element that had it before the lightbox opened. This is important for accessibility.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
returnFocus: false
});
lightbox.init();showAnimationDuration
Number, 333. Opening transition duration in milliseconds. Set to 0 to disable the opening animation.
Find an Example here.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
showAnimationDuration: 1000
});
lightbox.init();showHideAnimationType
String, "zoom". Adjust opening or closing transition. It supports three values:
-
zoom(default) -
fade(default if there is no thumbnail) -
none
Animations are automatically disabled, when user sets prefers-reduced-motion to reduce.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
showHideAnimationType: 'fade'
});
lightbox.init();spacing
Number, 0.1. The gap between slides, expressed as a fraction of the viewport width. The default of 0.1 means a gap of 10 % of the viewport width.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
spacing: 0.5, // 50% of viewport width
});
lightbox.init();trapFocus
Boolean, true. Keep the keyboard focus inside the lightbox while it is open. Together with returnFocus, this is the recommended setting for an accessible lightbox.
tapAction
Configures what happens when the user single-taps (tapAction) or double-taps (doubleTapAction) on a slide. Possible values include 'close', 'next', 'zoom', 'zoom-or-close' and false (no action).
Refer to the click and tap actions page for the full list and examples.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
tapAction: 'toggle-controls',
doubleTapAction: 'zoom'
});
lightbox.init();wheelToZoom
Boolean, undefined. By default, PhotoSwipe zooms the image only when the user holds Ctrl and turns the mouse wheel. When this option is enabled, simply turning the wheel zooms the image (no Ctrl key required).
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a',
wheelToZoom: true
});
lightbox.init();zoomAnimationDuration
Number, 333. Duration (in milliseconds) of the zoom-in / zoom-out transition. Set to 0 to disable the zoom animation.
Find an Example here.
zoomLevel
There are three related options that control how far the user can zoom into an image:
-
initialZoomLevel– the zoom level applied when a slide first opens. -
secondaryZoomLevel– the zoom level applied after a single zoom click or tap. -
maxZoomLevel– the maximum zoom level the user can reach by pinching, double-tapping, or rolling the mouse wheel.
Each option accepts a number (e.g. 2 for 200 %), one of the strings 'fit', 'fill', 'auto', or a function that returns one of those values. See Adjusting zoom level for details. The default values are described there too.
Methods
init
init()
Initialise the lightbox. Must be called exactly once for each lightbox instance. This call does not open the dialog itself; it only attaches the click handlers that will open the dialog later (by default a normal mouse click on a thumbnail). It is also the place where PhotoSwipe will preload images that are needed before the dialog opens.
const lightbox = new PhotoSwipeLightbox({
// options
});
// you may bind events here
lightbox.init();destroy
destroy()
Removes every event listener that the lightbox has attached and closes the lightbox if it is currently open. After this call the instance can no longer be used. To reopen the lightbox you have to create a new PhotoSwipeLightbox and call init() 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)
Programmatically open PhotoSwipe at a given slide. Use this when you need to open the lightbox from code (for example from a button click) instead of waiting for the user to click a thumbnail.
Arguments:
-
index(number) – Zero-based index of the slide to open. -
dataSource(optional,DataSource) – The gallery whose slides should be shown. Use this only if you want to override the default gallery. -
point(optional,{ x: number, y: number }) – Pixel coordinates of the click that opened the lightbox. By default this is{ x: e.clientX, y: e.clientY }of the original click event.
If you use the gallery and children options, and you omit the second argument, PhotoSwipe will use the first matching gallery element. To open a specific gallery element instead, pass it as the data source: { 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')
});
// Alternatively you can simply trigger the native click:
// document.querySelector('#gallery--with-button a:nth-of-type(2)').click();
};Events
PhotoSwipe Lightbox lets you react to a number of events. All event handlers can be attached directly to the lightbox instance with lightbox.on(eventName, callback). They are forwarded to the PhotoSwipe core automatically as soon as the dialog opens.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery_id',
pswpModule: PhotoSwipe,
children: 'a'
});
lightbox.on('change', () => {
// runs every time the user moves to another slide
console.log('current index:', lightbox.pswp.currIndex);
});
lightbox.init();Initialization events
These events fire while the lightbox is opening, in the order shown below:
beforeOpen-
PhotoSwipe is about to open. Use it to prepare data before any UI is created.
firstUpdate-
The DOM structure has been built and the initial slide index is set. You can change the initial index here.
initialLayout-
PhotoSwipe is measuring sizes. If you need to read element dimensions with
getBoundingClientRect, do it here. change-
A slide has become active. Fires both at first open and whenever the user navigates to another slide.
afterInit-
PhotoSwipe is fully initialised; the opening transition is now running.
bindEvents-
PhotoSwipe has finished binding its DOM event listeners (pointer events, wheel, keyboard, etc.).
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-init-events',
pswpModule: PhotoSwipe,
children: 'a'
});
lightbox.on('beforeOpen', () => {
console.log('beforeOpen');
});
lightbox.on('firstUpdate', () => {
console.log('firstUpdate');
});
lightbox.on('initialLayout', () => {
console.log('initialLayout');
});
lightbox.on('change', () => {
console.log('change');
});
lightbox.on('afterInit', () => {
console.log('afterInit');
});
lightbox.on('bindEvents', () => {
console.log('bindEvents');
});
lightbox.init();Opening and closing transitions
These events fire even when the corresponding transition is disabled (for example when showAnimationDuration is 0).
openingAnimationStart-
The opening animation has just started.
openingAnimationEnd-
The opening animation has finished. The lightbox is now fully open and ready to receive user input.
closingAnimationStart-
The closing animation has just started.
closingAnimationEnd-
The closing animation has finished. The lightbox is no longer visible.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-opening-closing-events',
pswpModule: PhotoSwipe,
children: 'a'
});
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
close-
PhotoSwipe is starting to close. This is the right moment to unbind listeners that were added on open.
destroy-
PhotoSwipe is fully closed and its DOM nodes are about to be removed. Tear down anything that should not outlive the lightbox here.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-closing-events',
pswpModule: PhotoSwipe,
children: 'a'
});
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 events
These events report low-level pointer (mouse, pen, touch) input.
pointerDown/pointerMove/pointerUp-
Fire on the equivalent native pointer event. The original DOM event is available as
e.originalEvent. pinchClose-
Fires while the user is closing the lightbox with a pinch gesture. Calling
e.preventDefault()cancels the gesture. verticalDrag-
Fires while the user is closing the lightbox with a vertical drag. Calling
e.preventDefault()cancels the gesture.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-pointer-events',
pswpModule: PhotoSwipe,
children: 'a'
});
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 prevented with e.preventDefault()
console.log('pinchClose', e.bgOpacity);
});
lightbox.on('verticalDrag', (e) => {
// triggered when using vertical drag to close gesture
// can be prevented with e.preventDefault()
console.log('verticalDrag', e.panY);
});
lightbox.init();Slide content events
These events let you observe (and in many cases override) how slide content is loaded, resized and added to the page. Refer to the Custom Content section of the official docs for full examples.
contentInit-
A new content object has just been created.
contentLoad-
Content is about to start loading. Can be cancelled with
e.preventDefault(). Useful when you want to provide a custom element oncontent.element. contentLoadImage-
Same as
contentLoad, but only fires for image content. loadComplete-
Content has finished loading.
contentResize-
Content is about to be resized. Can be cancelled.
imageSizeChange-
The displayed size of an image content has changed (the image element is on
content.element). contentLazyLoad-
Lazy loading of a piece of content is starting. Can be cancelled.
contentAppend-
Content is about to be appended to the DOM. Can be cancelled if you want to do this yourself.
contentActivate/contentDeactivate-
Fired when a piece of content becomes the current slide / stops being the current slide. Both can be cancelled.
contentRemove-
Content is about to be removed from the DOM. Can be cancelled.
contentDestroy-
Content is about to be destroyed. Can be cancelled.
const lightbox = new PhotoSwipeLightbox({
gallery: '#gallery--test-content-events',
pswpModule: PhotoSwipe,
children: 'a'
});
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 }) => {
console.log('imageSizeChange', content, width, height, slide, slide.index);
});
lightbox.on('contentLazyLoad', ({ content }) => {
console.log('contentLazyLoad', 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('contentDestroy', ({ content }) => {
console.log('contentDestroy', content);
});
lightbox.init();Captions
PhotoSwipe does not show captions out of the box, but a small plugin called PhotoSwipe Dynamic Caption adds that feature. The plugin automatically places the caption text either below or to the right of the image, depending on how much space is available. It works best for short to medium-length captions and only for images that use the default fit scale mode.
For accessibility, make sure that important caption text is also available outside of PhotoSwipe – for example by setting an alt attribute on the thumbnail image or by linking the caption to the thumbnail with aria-labelledby.
Parameters
The Dynamic Caption plugin reads its caption text from a hidden element inside each slide. By default it looks for an element with the CSS class .pswp-caption-content and uses its inner HTML as the caption. If no such element is found, the plugin falls back to the alt attribute of the thumbnail image.
The minimum HTML that the plugin expects on each slide looks like this:
<a href="path/to/large-image.jpg" data-pswp-width="1024" data-pswp-height="768">
<img src="path/to/thumbnail.jpg" alt="" />
<span class="pswp-caption-content">Caption content</span>
</a>You can also build the caption text programmatically by passing a function as captionContent. The function receives the current slide object and must return a string of HTML (or plain text):
captionContent: (slide) => {
return slide.data.element.querySelector('img').getAttribute('alt');
}| Name | Type | Default | Description | Example |
|---|---|---|---|
| string | function |
| Where to read the caption text from. If a string is supplied it is used as a CSS selector and the plugin reads the inner HTML of the matching element. If the element is not found, the plugin uses the |
| string |
| Position of the caption. Allowed values are
|
| number | function | 600 | Window width (in pixels) below which the mobile caption layout is used. May also be a function that returns Example |
| number | 20 | When the caption’s |
| number | 0.3 | Controls when the mobile caption switches to an overlap layout. The value is a ratio between 0 and 1. With the default |
| boolean |
| When set to |
Styling
The caption element always has the CSS class pswp__dynamic-caption. Depending on its current position the plugin adds one of the following modifier classes:
-
pswp__dynamic-caption—below– caption is below the image. -
pswp__dynamic-caption—aside– caption is to the right of the image. -
pswp__dynamic-caption—mobile– caption is pinned to the bottom of the viewport (the default mobile layout).
If the caption sits near the left horizontal edge it additionally gets the class pswp__dynamic-caption—on-hor-edge.
You can adjust the look of the captions in the plugin CSS file (media queries are welcome):
.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;
}Internally, the plugin decides where to place the caption like this:
-
It compares the amount of free horizontal space and free vertical space around the image.
-
If there is more vertical space:
-
The caption width is set to the width of the image.
-
The class
pswp__dynamic-caption—belowis added so its size can be adjusted via CSS. -
The caption height is measured.
-
If the caption fits without moving the image, it is shown right below the image.
-
If it does not fit, the pan area height is reduced by the height of the caption to make room.
-
-
If there is more horizontal space:
-
The class
pswp__dynamic-caption—asideis added so its size can be adjusted via CSS. -
The caption width is measured.
-
If the caption fits next to the image without moving it, it is shown on the right side.
-
If it does not fit, the pan area width is reduced by the caption width to make room.
-
If the mobileLayoutBreakpoint is met:
-
The caption height is measured at 100 % of the available width.
-
The pan area height is reduced so the caption fits below the image.
-
The remaining horizontal space is checked.
-
If too much horizontal space is left over (see
mobileCaptionOverlapRatio), the caption simply overlaps the image and the image is left at its default position.