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. |
Lightbox<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 |
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.