Vue Lightbox

Full-screen image & video gallery lightbox for Vue 3, built on @reelkit/vue-lightbox.

View live demo →

Features

Images & Video
Built-in video slide support
Touch Gestures
Swipe to navigate
Swipe to Close
Swipe up to dismiss
Keyboard Nav
Arrow keys + Escape
Fullscreen
Cross-browser API
Transitions
Slide, fade, flip, zoom-in
Preloading
±2 neighbours prefetched
Sound Toggle
Per-slide mute/unmute
Loading States
Spinner + custom slot
Error Handling
Error icon + custom slot
Scoped Slots
6 customisable slot zones
v-model
v-model:is-open two-way binding

Installation

bash

Don't forget to import the styles:

typescript
Icons
The default controls use lucide-vue-next for icons. If you prefer a different icon library, use the #controls and #navigation scoped slots to provide your own.

Basic Usage

Import the stylesheet and the LightboxOverlay component, then drive open/close with v-model:is-open.

App.vue

Scoped Slots

Six named scoped slots allow full customisation of the overlay surfaces. Omit the slot to keep the built-in default; provide nothing inside the slot (e.g. via v-if="false") to hide that section entirely.

SlotScopeDescription
#slideSlideSlotScopeReplace individual slide content (required for video slides)
#controlsControlsSlotScopeReplace the top controls bar (close, counter, fullscreen)
#navigationNavigationSlotScopeReplace the prev/next navigation arrows
#infoInfoSlotScopeReplace the bottom title/description gradient overlay
#loadingLoadingSlotScopeCustom loading indicator
#errorErrorSlotScopeCustom error indicator
vue

Video Support

Video slides are opt-in so the default bundle stays free of audio/video wiring. Call useVideoSlideRenderer(items) and forward the returned VideoSlideRenderer / VideoControlsRenderer into the overlay's #slide and #controls slots. Wrap the overlay in the returned SoundProvider so the built-in sound toggle has a context.

vue
The shared <video> element powering video slides uses the same pattern as the vue reel-player — playback continues across slide changes on iOS without requiring a per-slide user gesture.

Fullscreen

Use useFullscreen from @reelkit/vue to observe or toggle fullscreen state on a referenced element. The lightbox drives its built-in fullscreen button through the same composable.

vue

LightboxOverlay Props

PropTypeDefaultDescription
isOpenbooleanrequiredControls visibility; when false the overlay is removed from the DOM. Bindable via v-model:is-open.
itemsLightboxItem[]requiredArray of items (images or videos)
initialIndexnumber0Zero-based index of the initially visible item
transitionFnTransitionTransformFnslideTransitionSlide transition function. Import a built-in (slideTransition, flipTransition, lightboxFadeTransition, lightboxZoomTransition) or pass a custom one. Defaults to slideTransition when omitted.
showInfobooleantrueWhether to render the title/description info overlay
showControlsbooleantrueWhether to render the top controls bar (close, counter, fullscreen)
showNavigationbooleantrueWhether to render the prev/next navigation arrows (desktop only)
transitionDurationnumber300Slide animation duration in ms
swipeDistanceFactornumber0.12Minimum swipe distance fraction (0–1) to trigger slide change
swipeToCloseDirection'up' | 'down''up'Direction of the swipe-to-close gesture on mobile
loopbooleanfalseWhether the slider wraps from the last slide back to the first
enableNavKeysbooleantrueEnable keyboard arrow-key navigation
enableWheelbooleantrueEnable mouse-wheel navigation
wheelDebounceMsnumber200Debounce duration for wheel events in ms
ariaLabelstring'Image gallery'Accessible label for the dialog region

LightboxOverlay Events

EventPayloadDescription
closevoidEmitted when the user closes the lightbox
slide-changenumberEmitted with the new active slide index after a change
api-readyLightboxApiEmitted once the slider is ready, exposing the imperative API
update:is-openbooleanEmitted on close; enables v-model:is-open

LightboxItem Interface

FieldTypeRequiredDescription
srcstringyesURL of the image or video
type'image' | 'video'noItem type. Defaults to 'image'
posterstringnoThumbnail image for video items
titlestringnoTitle shown in the info overlay
descriptionstringnoDescription shown below the title
widthnumbernoIntrinsic image width in pixels
heightnumbernoIntrinsic image height in pixels

Slot Scope Types

TypeFields
SlideSlotScope{ item, index, size: [number, number], isActive, onReady, onWaiting, onError }
ControlsSlotScope{ item, activeIndex, count, isFullscreen, onClose, onToggleFullscreen }
NavigationSlotScope{ item, activeIndex, count, onPrev, onNext }
InfoSlotScope{ item, index }
LoadingSlotScope{ item, activeIndex }
ErrorSlotScope{ item, activeIndex }

Transitions

Pass any TransitionTransformFn via the transition-fn prop. Importing only the transition you use lets the bundler tree-shake the rest. Defaults to slideTransition when omitted.

FunctionDescription
slideTransitionDefault. Horizontal translate between slides; re-exported from @reelkit/vue.
lightboxFadeTransitionCrossfade with a subtle horizontal nudge. Local to @reelkit/vue-lightbox.
flipTransition3D flip around the Y-axis; re-exported from @reelkit/vue.
lightboxZoomTransitionIncoming slide scales 70% → 100% with fade. Local to @reelkit/vue-lightbox.
vue

Content Loading & Error Handling

When you take over rendering via the #slide slot, three lifecycle callbacks are available on the slot scope to report loading state. The lightbox tracks per-slide state and shows a spinner or error icon accordingly. A content preloader caches broken URLs so revisiting a failed slide skips the retry.

Lifecycle callbacks

CallbackTypeDescription
onReady() => voidNotify that the slide content has loaded successfully (e.g. image decoded)
onWaiting() => voidNotify that the slide content is loading/buffering (shows spinner)
onError() => voidNotify that the slide content failed to load (shows error icon)

Wiring callbacks in #slide

vue

Custom loading slot

Use the #loading slot to replace the default spinner.

vue

Custom error slot

Use the #error slot to replace the default broken-image icon.

vue

CSS Classes

All CSS classes are plain (not scoped), so they can be targeted with higher-specificity selectors in a stylesheet loaded after @reelkit/vue-lightbox/styles.css. For color, size, and z-index changes, prefer the CSS custom properties documented in the Theming section below.

ClassComponentDescription
.rk-lightbox-overlayOverlayRoot container (full-screen backdrop)
.rk-lightbox-top-shadeOverlayTop gradient scrim behind controls
.rk-lightbox-spinnerOverlayDefault loading spinner
.rk-lightbox-errorOverlayError state container (broken image)
.rk-lightbox-error-textOverlayError state text label
.rk-lightbox-controls-leftControlsTop-left controls container
.rk-lightbox-btnControlsControl button (fullscreen, sound, etc.)
.rk-lightbox-closeControlsClose button
.rk-lightbox-counterControlsImage counter chip
.rk-lightbox-navNavigationNavigation arrow (both prev and next)
.rk-lightbox-nav-prevNavigationPrevious arrow
.rk-lightbox-nav-nextNavigationNext arrow
.rk-lightbox-infoInfoTitle / description container
.rk-lightbox-info-titleInfoImage title
.rk-lightbox-info-descriptionInfoImage description
.rk-lightbox-slideSlideSlide container
.rk-lightbox-imgSlideImage element
.rk-lightbox-video-containerVideoSlideVideo slide container (opt-in)
.rk-lightbox-video-elementVideoSlideVideo element (opt-in)
.rk-lightbox-video-posterVideoSlideVideo poster image (opt-in)

Theming

Override any --rk-lightbox-* CSS custom property on :root (or any ancestor of .rk-lightbox-overlay) to retheme. Direct declarations on .rk-lightbox-overlay would shadow inherited values, so keep overrides on an ancestor selector.

TokenDefaultControls
--rk-lightbox-overlay-bg#000Backdrop color
--rk-lightbox-overlay-z9999Overlay z-index
--rk-lightbox-top-shade-height80pxTop scrim height
--rk-lightbox-top-shade-bglinear-gradient(rgba(0,0,0,0.6), transparent)Top scrim gradient
--rk-lightbox-edge-padding16pxEdge inset for close / nav / controls
--rk-lightbox-btn-bgrgba(0, 0, 0, 0.5)Default background for close / nav / small buttons
--rk-lightbox-btn-bg-hoverrgba(255, 255, 255, 0.2)Hover background for close / nav / small buttons
--rk-lightbox-btn-fg#fffIcon color for close / nav / small buttons
--rk-lightbox-btn-size36pxSmall button size (fullscreen toggle, etc.)
--rk-lightbox-close-size40pxClose button size
--rk-lightbox-nav-size48pxPrev / next arrow size
--rk-lightbox-nav-opacity0.7Idle opacity of prev / next arrows
--rk-lightbox-counter-bgrgba(0, 0, 0, 0.5)Counter chip background
--rk-lightbox-counter-fg#fffCounter text color
--rk-lightbox-info-bglinear-gradient(transparent, rgba(0,0,0,0.8))Caption scrim gradient
--rk-lightbox-title-size18pxTitle font size
--rk-lightbox-description-size14pxDescription font size
--rk-lightbox-video-bg#000Letterbox background behind <video>
css

Accessibility

The overlay root is a modal dialog (role="dialog", aria-modal="true"). Set the aria-label prop to change the screen-reader announcement; it defaults to "Image gallery". Each slide carries role="group", aria-roledescription="slide", and an aria-label derived from the position (e.g. "Image 2 of 5").

The lightbox captures focus on open and returns it to the trigger on close. Tab and Shift+Tab cycle through focusable elements inside; focus that escapes (click outside, programmatic focus) gets pulled back. Implemented with captureFocusForReturn and createFocusTrap from @reelkit/vue.

Keyboard Shortcuts

KeyAction
ArrowLeftPrevious image
ArrowRightNext image
EscapeClose lightbox (or exit fullscreen if active)