A composable lightbox for Vue 3, built on PhotoSwipe.
This library allows you to dynamically create and manage lightboxes with fully customizable tools and content slots — simple map a type to a component to use it in the lightbox!
- Fully customizable lightbox using Vue components.
- Supports any type of content: images, video, audio, HTML, interactive Vue components, etc.
- Dynamically add tools and content slots.
- Built on top of PhotoSwipe for smooth and responsive galleries.
This package requires Vue 3 and PhotoSwipe.
Install via npm:
npm install vue-composable-lightboxIn your application entry point (app.js):
import { createApp } from 'vue'
import App from './App.vue'
import 'photoswipe/style.css'
import VueComposableLightboxPlugin from 'vue-composable-lightbox'
const app = createApp(App)
// Optionally add default renderers and tools
app.use(VueComposableLightboxPlugin, {
tools: [LightboxZoomButton],
content: {
audio: LightboxAudio,
video: LightboxVideo,
},
})
app.mount('#app')Import and initialize the composable in your component:
import { useLightbox } from 'vue-composable-lightbox'
import LightboxZoomButton from '../LightboxZoomButton.vue'
import LightboxVideo from '../LightboxVideo.vue'
import LightboxAudio from '../LightboxAudio.vue'
const { open } = useLightbox({
tools: [LightboxZoomButton],
content: {
audio: LightboxAudio,
video: LightboxVideo,
},
photoswipeConstructorArgs: {}, // Optional PhotoSwipe options
})Content items can be anything: images, videos, audio, HTML, or interactive Vue components. If you want to use a custom renderer, each item must include a vclType matching a key in your content mapping.
const contentItems = [
{
id: 1,
original_url: 'https://example.com/image1.jpg',
preview_url: 'https://example.com/image1-preview.jpg',
custom_properties: { width: 1920, height: 1080 },
},
{
id: 2,
original_url: 'https://example.com/video.mp4',
preview_url: 'https://example.com/video-preview.jpg',
custom_properties: { width: 1280, height: 720 },
vclType: 'video',
},
]function openLightbox() {
open(contentItems)
}When using the default image renderer, a content item should have:
{
id: number,
original_url: string,
preview_url: string,
custom_properties: {
width: number,
height: number,
},
srcset?: string, // Optional for responsive images
}You can pass Vue components for specific vclType values via the content option. Each component receives a single prop data containing the original content object passed to open().
const { open } = useLightbox({
content: {
video: CustomVideoPlayComponent,
},
})
const contentItems = [
{
original_url: '/video.mp4',
preview_url: '/video-preview.jpg',
vclType: 'video',
},
]<template>
<video :poster="data.preview_url" :src="data.original_url" controls />
</template>
<script setup>
const props = defineProps({
data: {
type: Object,
required: true,
},
})
</script>useLightbox(options: LightboxOptions)open(content: Array<any> | any, index: number = 0): Opens the lightbox with the given content at the optional starting index.
interface LightboxOptions {
/**
* An array of Vue components to render as tools in the lightbox toolbar.
* Example: [LightboxZoomButton, LightboxDownloadButton]
*/
tools?: Array<Component>
/**
* A mapping of content types to Vue components for custom rendering.
* Each item in the content array passed to `open(...)` should include a `vclType`
* that matches a key in this mapping.
* Example: { video: LightboxVideo, audio: LightboxAudio }
*/
content?: { [type: string]: Component }
/**
* Additional arguments passed directly to the PhotoSwipeLightbox constructor.
* Allows customizing padding, UI behavior, and other PhotoSwipe options.
*/
photoswipeConstructorArgs?: Record<string, any>
/**
* Optional configuration for the gallery items.
*/
config?: {
/**
* Key in the content item object representing the source URL.
* Default: 'original_url'
*/
srcKey?: string
/**
* Key in the content item object representing the preview/poster image URL.
* Default: 'preview_url'
*/
posterKey?: string
/**
* Default height used if `custom_properties.height` is not provided on a content item.
*/
defaultHeight: number
/**
* Default width used if `custom_properties.width` is not provided on a content item.
*/
defaultWidth: number
}
}import { useLightbox } from 'vue-composable-lightbox'
import LightboxZoomButton from '../LightboxZoomButton.vue'
import LightboxVideo from '../LightboxVideo.vue'
const { open } = useLightbox({
tools: [LightboxZoomButton],
content: {
video: LightboxVideo,
},
photoswipeConstructorArgs: {
padding: { top: 50, bottom: 50, left: 50, right: 50 }
},
config: {
srcKey: 'original_url',
posterKey: 'preview_url',
defaultHeight: 800,
defaultWidth: 1200,
}
})This project is licensed under the MIT License. See the LICENSE file for details.