Angular Lightbox

Full-screen image & video gallery lightbox for Angular, built on @reelkit/angular-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
Adjacent images prefetched
Sound Toggle
Per-slide mute/unmute
Loading States
Spinner + custom slot
Error Handling
Error icon + custom slot
Template Slots
6 customizable slot zones
OnPush
Angular signals + OnPush
URL State
Shareable, bookmarkable links

Installation

bash
Icons
The default controls use lucide-angular for icons. If you prefer a different icon library, use the rkLightboxControls and rkLightboxNavigation template slots to provide your own.

Basic Usage

Import the styles and the RkLightboxOverlayComponent standalone component into your component's imports array.

gallery.component.ts

Template Slots

Four template slot directives allow full customization of the overlay UI without forking the component. Each slot receives a strongly-typed context object.

DirectiveContext TypeDescription
[rkLightboxControls]LightboxControlsContextReplace the top controls bar (close button, counter, fullscreen toggle)
[rkLightboxNavigation]LightboxNavContextReplace the prev/next navigation arrows
[rkLightboxInfo]LightboxInfoContextReplace the bottom title/description gradient overlay
[rkLightboxSlide]LightboxSlideContextReplace individual slide content (required for video slides)
[rkLightboxLoading]{ $implicit: activeIndex, item }Custom loading indicator
[rkLightboxError]{ $implicit: activeIndex, item }Custom error indicator
typescript

Video Support

Video slides require opting in via the rkLightboxSlide template slot and the RkLightboxVideoSlideComponent. This design avoids bundling the video player for galleries that only need images.

typescript

Fullscreen

Use fullscreenSignal, requestFullscreen, and exitFullscreen from @reelkit/angular to observe or toggle fullscreen state.

typescript

URL State

RkLightboxUrlOverlayComponent is a separate component whose open state lives in the address bar. Build a controller with createOverlayUrlState and hand it over as [controller]: the gallery opens itself when the parameter names a slide and closes when it goes away. Links are shareable, and the back button closes the gallery instead of leaving the page.

Built-in keys
You can address slides with a built-in key — spread urlIndexKey (by position) or urlStableIdKey (by a stable id) into the controller — both re-exported from @reelkit/angular. See the URL State guide and Core API.
typescript

Call it in an injection context — a field initialiser or the constructor. It attaches immediately and releases through DestroyRef, so a component destroyed while the gallery is open leaves no listener behind. Full options live in the Angular API reference.

  • Opening pushes one history entry. Paging slides replaces it, so N steps add no entries and one back step always leaves the gallery.
  • Back closes only when the gallery was opened from within the app — the link pushed an entry. A shared link opened directly in a fresh tab has no history behind it, so browser-back leaves the site; the ✕ button or Escape removes the parameter in place and stays.
  • A parameter naming no slide — a stale bookmark, a hand-edited value — is dropped from the URL rather than left asserting a slide that cannot open.
  • Template slots work unchanged: the url component runs the six slot queries itself and forwards each template to the gallery, so rkLightboxControls and its siblings sit inside it exactly as they would inside rk-lightbox-overlay.
  • In a routed application pass an adapter built on Router. Writing history behind the Router leaves its location stale and its next navigation drops the parameter.

In a routed app, pass an adapter. Writing history behind the Router leaves its location stale and its next navigation drops the parameter, so build an adapter on Router and pass it as adapter:

typescript

Stable links. The index is positional — a bookmarked ?photo=3 opens a different image once the list is reordered. urlStableIdKey keys by each item's stable id, scanning the live list — one call covers the common case.

typescript

Pass hashCodec: base64UrlCodec to base64url-encode the id in the URL — reversible obfuscation, not a cryptographic hash.

Key by a different field (a slug), or page an infinite feed with locateAsync, and build the codec (wire) and locator (lookup) yourself:

typescript

Infinite or paginated galleries. locate is synchronous, so it only answers for images already loaded — a shared link to image 400 of a feed that has loaded 20 comes up empty. locateAsync is the fallback, called only when locate misses: load the pages you need, then return the index the identity turned out to have. While it is pending the gallery stays closed and the parameter is left alone, so the deep link survives the fetch; null or a rejection drops the parameter.

Shortcut
Keying by the item’s id? Skip the hand-rolled codec and locator — pass locateAsync straight to urlStableIdKey({ items, locateAsync }) (it fetches on a miss, then returns the index). The fuller version below is for keying by another field, or for full control.
typescript

RkLightboxUrlOverlayComponent Inputs

Takes every input of rk-lightbox-overlay except isOpen, replaced by a controller. Outputs are the same closed and slideChange; the URL drives closing, so closed is a notification rather than the mechanism.

InputTypeDefaultDescription
controllerUrlStateControllerrequiredController from createOverlayUrlState. Its position decides whether the gallery is open and which slide it shows; the component writes back through it on slide change and on close.

RkLightboxOverlayComponent Inputs

InputTypeDefaultDescription
isOpenbooleanrequiredControls visibility; when false the overlay is removed from the DOM
itemsLightboxItem[]requiredArray of lightbox 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
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 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

RkLightboxOverlayComponent Outputs

OutputTypeDescription
closedEventEmitter<void>Emitted when the user closes the lightbox
slideChangeEventEmitter<number>Emitted when the active slide index changes

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

Template Slot Context Types

TypeFields
LightboxControlsContext{ item, onClose, activeIndex, count, isFullscreen, onToggleFullscreen }
LightboxNavContext{ item, onPrev, onNext, activeIndex, count }
LightboxInfoContext{ $implicit: LightboxItem, index }
LightboxSlideContext{ $implicit: LightboxItem, index, size: [number, number], isActive, onReady, onWaiting, onError }

Transitions

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

FunctionFromDescription
slideTransition@reelkit/angular-lightboxStandard horizontal slide (default)
lightboxFadeTransition@reelkit/angular-lightboxCrossfade between images
flipTransition@reelkit/angular-lightbox3D card flip effect
lightboxZoomTransition@reelkit/angular-lightboxZoom in from smaller to normal size
typescript

Content Loading & Error Handling

When using the rkLightboxSlide template slot, three lifecycle callbacks are available on the context 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 rkLightboxSlide

html

Custom Loading Template

Use the rkLightboxLoading directive to replace the default spinner.

html

Custom Error Template

Use the rkLightboxError directive to replace the default error icon.

html

CSS Classes

All CSS classes are plain (not scoped), so they can be targeted with higher-specificity selectors in a stylesheet loaded after @reelkit/angular-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-img-errorOverlayError state container (broken image)
.rk-lightbox-img-error-textOverlayError state text label
.rk-lightbox-swipe-hintOverlayMobile swipe hint
.rk-lightbox-emptyOverlayEmpty state text
.rk-lightbox-controls-leftControlsTop-left controls container
.rk-lightbox-btnControlsControl button (fullscreen, 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-titleInfoImage title
.rk-lightbox-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)
.rk-lightbox-video-errorVideoSlideVideo error state container

Theming

Every color, size, z-index, and transition lives in a CSS custom property. Override one or many at :root (or any ancestor of the lightbox) to retheme without touching component source. The tokens match the React lightbox, so overrides port between bindings.

TokenDefaultControls
--rk-lightbox-overlay-bg#000Full-screen backdrop color
--rk-lightbox-overlay-z9999Overlay z-index
--rk-lightbox-top-shade-height80pxTop gradient scrim height
--rk-lightbox-top-shade-bglinear-gradient(rgba(0,0,0,0.6), transparent)Top gradient scrim color
--rk-lightbox-edge-padding16pxEdge inset for close / nav / top-left controls
--rk-lightbox-controls-gap12pxGap between top-left controls
--rk-lightbox-transition0.2sButton hover transition duration
--rk-lightbox-blur8pxBackdrop blur radius for buttons / chips
--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-fg#fffCounter text color
--rk-lightbox-counter-bgrgba(0, 0, 0, 0.5)Counter chip background
--rk-lightbox-counter-size14pxCounter font size
--rk-lightbox-counter-padding6px 12pxCounter chip padding
--rk-lightbox-counter-radius20pxCounter chip border-radius
--rk-lightbox-spinner-size28pxDefault spinner width/height
--rk-lightbox-spinner-duration0.8sSpinner rotation duration
--rk-lightbox-error-fgrgba(255, 255, 255, 0.4)Error icon + text color
--rk-lightbox-info-bglinear-gradient(transparent, rgba(0,0,0,0.8))Caption scrim gradient
--rk-lightbox-info-padding24pxCaption inner padding
--rk-lightbox-title-size18pxTitle font size
--rk-lightbox-description-size14pxDescription font size
--rk-lightbox-hint-fgrgba(255, 255, 255, 0.5)Swipe hint text color
--rk-lightbox-hint-bgrgba(0, 0, 0, 0.3)Swipe hint chip background
--rk-lightbox-video-bg#000Letterbox background behind <video>

Drop the snippet below into a stylesheet loaded after @reelkit/angular-lightbox/styles.css.

css

Accessibility

The overlay root is a modal dialog (role="dialog", aria-modal="true"). Set the ariaLabel input 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 image title plus position.

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/core.

Keyboard Shortcuts

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