@reelkit/vue-lightbox

Full-screen image and video gallery lightbox for Vue 3 with touch gestures, transitions, and slot customization
1,394 43
Install
npm install @reelkit/vue-lightbox
Latest Version:0.4.1
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm
Maintainer: konstantin.kai

@reelkit/vue-lightbox

npm Bundle size Statement coverage Star on GitHub

An image lightbox on a phone: tapping a gallery thumbnail opens it full screen, two sideways swipes page to the third photo, and a swipe up closes it back to the gallery.

Full-screen image and video gallery lightbox for Vue 3. Horizontal swipe navigation, fullscreen toggle, opt-in video support, and four built-in transitions. ~4.9 kB gzip.

Live Demo

Installation

npm install @reelkit/vue-lightbox @reelkit/vue lucide-vue-next

Quick Start

<script setup lang="ts">
import { ref } from 'vue';
import { LightboxOverlay, type LightboxItem } from '@reelkit/vue-lightbox';
import '@reelkit/vue-lightbox/styles.css';

const open = ref(false);
const items: LightboxItem[] = [
  {
    src: 'https://example.com/image-01.jpg',
    title: 'Mountain River',
    description: 'A beautiful mountain river flowing through the forest',
    width: 1600,
    height: 1000,
  },
];
</script>

<template>
  <button @click="open = true">Open Gallery</button>
  <LightboxOverlay v-model:is-open="open" :items="items" />
</template>

Features

  • Horizontal swipe navigation (touch, mouse, keyboard, wheel)
  • Tree-shakable transitions — slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition (import only what you use)
  • Fullscreen toggle with two-step Escape (exit fullscreen → close)
  • Swipe-up-to-close on mobile
  • Opt-in video support via useVideoSlideRenderer
  • Opt-in slideshow — auto-advance plays the gallery on its own, with a PlayPauseButton and play() / pause() on the api
  • Opt-in download — show-download adds a DownloadButton that saves the active item, from downloadUrl when the preview is a resized copy
  • Desktop prev/next arrows with boundary hiding
  • Dialog a11y: role="dialog", aria-modal, focus trap + return
  • Themeable via --rk-lightbox-* CSS custom properties
  • Shareable URLs — LightboxUrlOverlay opens itself from the address bar

Scoped Slots

Slot Scope
slide item, index, size, isActive, autoAdvance, onReady, onWaiting, onError, onEnded
controls item, activeIndex, count, isFullscreen, isAutoAdvancing, isDownloading, onClose, onToggleFullscreen, onToggleAutoAdvance?, onDownload?
navigation item, activeIndex, count, onPrev, onNext
info item, index
loading item, activeIndex
error item, activeIndex

Props

Prop Type Default Description
isOpen boolean required Controls overlay visibility
items LightboxItem[] required Images/videos to display
initialIndex number 0 Starting slide index
ariaLabel string 'Image gallery' Dialog aria-label
transitionFn TransitionTransformFn slideTransition Slide transition fn (built-in or custom)
swipeToCloseDirection SwipeToCloseDirection 'up' Which way a swipe dismisses the lightbox
loop boolean false Enable infinite loop
enableNavKeys boolean true Arrow-key navigation
enableWheel boolean true Wheel navigation
wheelDebounceMs number 200 Wheel debounce duration (ms)
transitionDuration number 300 Animation duration (ms)
swipeDistanceFactor number 0.12 Swipe threshold (0-1)
showInfo boolean true Show title/description overlay
showControls boolean true Show controls bar
showNavigation boolean true Show prev/next arrows on desktop
autoAdvance boolean false Play the gallery as a slideshow
autoAdvanceInterval number 5000 Image time in a slideshow (ms), from load
showDownload boolean false Add a download button

Events

Event Payload Description
close void Emitted when the overlay closes
slide-change number Emitted after the active slide changes
api-ready LightboxApi Emitted with the imperative lightbox API
update:is-open boolean Emitted on close — enables v-model:is-open

The LightboxApi from api-ready (also on the template ref) has next(), prev(), goTo(), adjust(), observe(), unobserve(), close(), and play() / pause() for the slideshow.

Slideshow and download (opt-in)

<LightboxOverlay
  v-model:is-open="open"
  :items="items"
  auto-advance
  :auto-advance-interval="4000"
  show-download
/>

auto-advance counts each image's interval from the moment it has loaded, plays a video once and moves on when it ends, waits while the mouse rests on a control, during a swipe and while the page is hidden, and stops on the last slide unless loop is set. A PlayPauseButton joins the controls.

show-download adds a DownloadButton that saves the active item from downloadUrl (or src) under downloadName; a LightboxItem takes both as optional fields. The file is fetched so a cross-origin link still downloads; when the server sends no CORS headers it opens in a new tab instead.

Video support (opt-in)

<script setup lang="ts">
import { ref } from 'vue';
import {
  LightboxOverlay,
  useVideoSlideRenderer,
  type LightboxItem,
} from '@reelkit/vue-lightbox';
import '@reelkit/vue-lightbox/styles.css';

const open = ref(false);
const items: LightboxItem[] = [
  { src: '/image.jpg' },
  { type: 'video', src: '/clip.mp4', poster: '/clip.jpg' },
];
const { VideoSlideRenderer, VideoControlsRenderer, SoundProvider } =
  useVideoSlideRenderer(items);
</script>

<template>
  <SoundProvider>
    <LightboxOverlay v-model:is-open="open" :items="items">
      <template #slide="scope">
        <VideoSlideRenderer v-bind="scope" />
      </template>
      <template #controls="scope">
        <VideoControlsRenderer v-bind="scope" />
      </template>
    </LightboxOverlay>
  </SoundProvider>
</template>

URL-driven lightbox

LightboxUrlOverlay takes the same props except isOpen — the address bar owns the open state, so a shared link opens the gallery on the right image:

<script setup lang="ts">
import { LightboxUrlOverlay, type LightboxItem } from '@reelkit/vue-lightbox';
import { useOverlayUrlState, urlIndexKey } from '@reelkit/vue';
import '@reelkit/vue-lightbox/styles.css';

const props = defineProps<{ images: LightboxItem[] }>();

const photo = useOverlayUrlState({
  param: 'photo',
  ...urlIndexKey(() => props.images.length),
});
</script>

<template>
  <!-- Opening is a link — the overlay reads the URL and opens itself. -->
  <RouterLink
    v-for="(img, i) in props.images"
    :key="img.src"
    :to="`?photo=${i}`"
  >
    <img :src="https://raw.githubusercontent.com/KonstantinKai/reelkit/HEAD/img.src" />
  </RouterLink>

  <LightboxUrlOverlay :controller="photo" :items="props.images" />
</template>

In a vue-router application pass adapter: useVueRouterUrlAdapter() from @reelkit/vue/vue-router-url-adapter, otherwise the router's own location goes stale. Swap urlIndexKey for urlStableIdKey({ items: () => props.images }) to key the URL by image id.

Sub-components

For composing your own controls or slides: CloseButton, Counter, FullscreenButton, SoundButton, PlayPauseButton, DownloadButton, LightboxNavigation, ImageSlide, LightboxVideoSlide.

Keyboard Shortcuts

Key Action
ArrowLeft Previous slide
ArrowRight Next slide
Escape Exit fullscreen (if active), then close the lightbox

Documentation

Docs, runnable StackBlitz examples, and customization guides at reelkit.dev/docs/vue-lightbox.

Support

If ReelKit saved you some time, a star on GitHub would mean a lot — it's a small thing, but it really helps the project get noticed.

Star on GitHub

License

MIT

Related Packages

@reelkit/vue-reel-player

Full-screen vertical-swipe video/image reel player for Vue 3, inspired by Instag...

1,645 43
@reelkit/vue-stories-player

Instagram-style stories player overlay for Vue 3 with cube transitions and auto-...

766 43
@archpublicwebsite/gallery

Gallery lightbox component for Archipelago hotel websites

732
@lightgallery/vue

Native Vue 3 lightGallery over @lightgallery/headless

809 7,056

Version History

Version Released Vue License
0.4.1 >=3.0.0 MIT
0.4.0 >=3.0.0 MIT
0.3.4 >=3.0.0 MIT
0.3.3 >=3.0.0 MIT
0.3.2 >=3.0.0 MIT