Vize

Lightbox

Headless gallery lightbox on the Dialog family: keyboard, swipe, thumbnails, and preloading.

Package @vizejs/ui/lightbox
Maturity stable
Own the source vize lib pull lightbox
Requires context, controllable-state, dialog, id, image
Aliases lightbox, gallery, image viewer, media viewer, photo viewer
Covers WAI-ARIA Dialog (modal), WAI-ARIA Tabs (thumbnail picker), PhotoSwipe, yet-another-react-lightbox

Usage

import { LightboxClose, LightboxContent, LightboxCounter, LightboxImage, LightboxItem, LightboxNext, LightboxPrevious, Lightbox, LightboxRoot, LightboxThumbnail, LightboxThumbnails, LightboxTrigger } from "@vizejs/ui/lightbox";

Or copy the source into your project with vize lib pull lightbox (see Source Distribution).

API

LightboxClose

Source: src/families/media/lightbox/lightbox-close.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name. Defaults to the close message.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before closing. Call preventDefault() to keep the viewer open.

Slots

Slot Slot props Description
default LightboxPartSlotState Button content, e.g. an icon.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

LightboxContent

Source: src/families/media/lightbox/lightbox-content.vue

Props

Prop Type Default Description
to string | HTMLElement "body" CSS selector or element the viewer layer is moved into.
portalDisabled boolean false Render in place instead of teleporting.
swipeThreshold number 50 Minimum swipe travel in CSS pixels along the dominant axis.
ariaLabel string undefined Accessible dialog name. Defaults to the dialog message unless labelled by ids.
ariaLabelledby string undefined Space-separated ids that label the dialog, e.g. a visible caption.

Slots

Slot Slot props Description
default LightboxPartSlotState Viewer content: item, controls, counter, thumbnails. Receives the viewer state.

Exposed

Member Type Description
element HTMLDivElement | null Rendered stage element inside the dialog, while open.

LightboxCounter

Source: src/families/media/lightbox/lightbox-counter.vue

Slots

Slot Slot props Description
default LightboxCounterSlotState Position text. Defaults to the counter message, e.g. "3 of 10".

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

LightboxImage

Source: src/families/media/lightbox/lightbox-image.vue

Props

Prop Type Default Description
src (required) ImageSource required Image source or ordered fallback chain.
alt (required) string required Native alternative text.
placeholderDelay number 150 Milliseconds before the placeholder renders, avoiding a flash for cached images.

Slots

Slot Slot props Description
placeholder — Loading placeholder, e.g. a spinner or blurred preview.
fallback — Fallback after every source failed.

LightboxItem

Source: src/families/media/lightbox/lightbox-item.vue

Slots

Slot Slot props Description
default LightboxCounterSlotState Current media. Render the root slot's item here.

Exposed

Member Type Description
element HTMLDivElement | null Rendered item element.
id string Deterministic id referenced by thumbnails.

LightboxNext

Source: src/families/media/lightbox/lightbox-next.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name. Defaults to the next message.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the current item.

Slots

Slot Slot props Description
default LightboxPartSlotState Button content, e.g. an icon.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

LightboxPrevious

Source: src/families/media/lightbox/lightbox-previous.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name. Defaults to the previous message.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before navigation. Call preventDefault() to keep the current item.

Slots

Slot Slot props Description
default LightboxPartSlotState Button content, e.g. an icon.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

Source: src/families/media/lightbox/lightbox-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
items (required) readonly Item[] required Items shown by the viewer; the item type flows into every root slot.
open boolean | undefined undefined Controlled open state (v-model:open). undefined selects defaultOpen.
defaultOpen boolean false Initial open state for uncontrolled use.
index number | undefined undefined Controlled zero-based current index (v-model:index). undefined selects defaultIndex.
defaultIndex number 0 Initial index for uncontrolled use.
loop boolean false Wrap previous/next navigation at both ends.
dir LightboxDirection "ltr" Reading direction for arrow keys and swipes.
closeOnSwipeDown boolean true Let a downward touch swipe close the viewer.
preload number 1 Neighbours on each side warmed through getPreloadSrc while open.
getPreloadSrc ((item: Item) => string | undefined) | undefined undefined Returns the image URL to warm for an item. Preloading runs on the client only.
messages LightboxMessageOverrides | undefined undefined Localized strings.

Events

Event Payload Description
update:open [open: boolean] Fired when the open state requests a new controlled value.
update:index [index: number] Fired when the current index requests a new controlled value.
change [index: number, previous: number, reason: LightboxChangeReason] Fired after every distinct index request, with its cause.

Slots

Slot Slot props Description
default LightboxSlotState<Item> Triggers and the viewer content. Receives the inferred current item.

Exposed

Member Type Description
canGoNext —
canGoPrevious —
close —
count —
goTo —
index —
item —
items —
next —
open —
openAt —
previous —
state —

LightboxRoot<Item>

Source: src/families/media/lightbox/lightbox-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
items (required) readonly Item[] required Items shown by the viewer; the item type flows into every root slot.
open boolean | undefined undefined Controlled open state (v-model:open). undefined selects defaultOpen.
defaultOpen boolean false Initial open state for uncontrolled use.
index number | undefined undefined Controlled zero-based current index (v-model:index). undefined selects defaultIndex.
defaultIndex number 0 Initial index for uncontrolled use.
loop boolean false Wrap previous/next navigation at both ends.
dir LightboxDirection "ltr" Reading direction for arrow keys and swipes.
closeOnSwipeDown boolean true Let a downward touch swipe close the viewer.
preload number 1 Neighbours on each side warmed through getPreloadSrc while open.
getPreloadSrc ((item: Item) => string | undefined) | undefined undefined Returns the image URL to warm for an item. Preloading runs on the client only.
messages LightboxMessageOverrides | undefined undefined Localized strings.

Events

Event Payload Description
update:open [open: boolean] Fired when the open state requests a new controlled value.
update:index [index: number] Fired when the current index requests a new controlled value.
change [index: number, previous: number, reason: LightboxChangeReason] Fired after every distinct index request, with its cause.

Slots

Slot Slot props Description
default LightboxSlotState<Item> Triggers and the viewer content. Receives the inferred current item.

Exposed

Member Type Description
open boolean Whether the viewer is open.
index number Zero-based current item index.
count number Number of items.
canGoPrevious boolean Whether previous navigation is available.
canGoNext boolean Whether next navigation is available.
state LightboxState Stable state token.
item Item | undefined Current item, or undefined without items.
items readonly Item[] Every item.
openAt (index: number) => boolean Open at an index. Reports whether open or index changed.
close () => boolean Close the viewer. Reports whether it was open.
goTo (index: number) => boolean Show one item. Reports whether the index changed.
next () => boolean Show the next item (wrapping with loop).
previous () => boolean Show the previous item (wrapping with loop).

LightboxThumbnail

Source: src/families/media/lightbox/lightbox-thumbnail.vue

Props

Prop Type Default Description
index (required) number required Zero-based item index this thumbnail shows.
ariaLabel string undefined Accessible name. Defaults to the thumbnail message.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before selection. Call preventDefault() to keep the current item.

Slots

Slot Slot props Description
default LightboxIndexSlotState Thumbnail content, e.g. a small image.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

LightboxThumbnails

Source: src/families/media/lightbox/lightbox-thumbnails.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible tablist name. Defaults to the thumbnails message.

Slots

Slot Slot props Description
default LightboxPartSlotState LightboxThumbnail children.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

LightboxTrigger

Source: src/families/media/lightbox/lightbox-trigger.vue

Props

Prop Type Default Description
index (required) number required Zero-based item index opened by this trigger.
ariaLabel string undefined Accessible name for thumbnail-only triggers without an alt text.

Events

Event Payload Description
click [nativeEvent: MouseEvent] Fired before opening. Call preventDefault() to keep the viewer closed.

Slots

Slot Slot props Description
default LightboxIndexSlotState Trigger content, typically a thumbnail image.

Exposed

Member Type Description
disabled —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

Behavior

Normative state x input -> outcome table for lightbox-root.vue, lightbox-trigger.vue, lightbox-content.vue, lightbox-item.vue, lightbox-image.vue, lightbox-previous.vue, lightbox-next.vue, lightbox-close.vue, lightbox-counter.vue, lightbox-thumbnails.vue, and lightbox-thumbnail.vue (@vizejs/ui/lightbox). Every row is proven by the named test.

The viewer is built on the Dialog family: LightboxRoot drives a DialogRoot, and LightboxContent renders DialogPortal + DialogContent. It therefore inherits modal focus containment, focus return, Escape, outside dismissal, inert outside content, and scroll locking. LightboxRoot is generic over items, so the root slot's item keeps the consumer's item type.

ID State Input Outcome Evidence
L1 closed trigger click / Close opens a labelled modal dialog at the trigger's index (reason trigger); closing returns focus to that trigger renders closed triggers that open the dialog at their item and restore focus
L2 open Previous / Next moves one item, disables at the ends, wraps with loop previous and next navigate, disable at the ends, and wrap with loop
L3 open Arrow / Home / End arrows follow dir; Home/End jump; keys in text fields or with modifiers are ignored arrow, Home, and End keys navigate with reading direction and skip text fields
L4 open Escape the dialog layer closes the viewer and emits update:open Escape closes through the dialog layer
L5 open touch/pen swipe horizontal swipes past swipeThreshold navigate (RTL aware); a downward swipe closes unless disabled; mouse and cancelled gestures are ignored touch swipes navigate by direction and a downward swipe closes
L6 open thumbnails a roving tablist selects items on click and arrows/Home/End, moves focus, and is not double-handled by the stage thumbnails form a roving tablist that selects and focuses items
L7 controlled v-model:open / v-model:index requests are emitted while controlled values win; out-of-range indexes clamp controlled open and index win until the parent accepts the request
L8 open index changes getPreloadSrc warms preload neighbours once each, on the client only, never while closed preloads neighbouring images on the client while open
L9 messages render every accessible name, the counter, and the slide role description come from typed messages; ariaLabelledby replaces the dialog label localized messages label every control
L10 controls / API preventDefault() / expose controls honor preventDefault(); the instance exposes typed state and openAt/close/goTo/next/previous controls honor preventDefault and exposes typed imperative controls
L11 portal open content teleports to body by default teleports the viewer to the document body by default
L12 missing provider setup parts fail closed with a context diagnostic compound parts require a matching root provider
L13 pure helpers state index resolution, preload neighbours, swipe classification, and messages are deterministic resolves indexes, preload neighbours, swipes, and messages
L14 SSR isolated requests closed and open markup are byte-identical renders byte-identical closed and open lightbox markup across isolated SSR requests
L15 SSR / hydration hydrate open server markup hydrates without warnings or node replacement hydrates open lightbox markup without warnings or node replacement
L16 types compile item types flow into slots and exposes; reasons, swipes, and messages are closed lightbox.types.test-d.ts

The counter is a polite live region, so position changes are announced. LightboxImage wraps the Image family: eager loading, safe source chains, a delayed placeholder, and a fallback.