Lightbox
Full-screen image viewer on the overlay stack: open from a thumbnail, step through a gallery with wrapping prev/next navigation, zoom to 2x with drag-to-pan, and dismiss with Escape or a backdrop click.
<arc-lightbox> Overview
>
Lightbox displays a gallery of images at full screen, above the page behind a blurred backdrop. It shares the overlay infrastructure with Modal and Sheet: keyboard focus is trapped while open, page scroll is locked, Escape and a backdrop click dismiss, and focus returns to the trigger element on close. Open it from a thumbnail with `show(index)`, or set `open` and `index` directly.
The gallery is supplied through the `images` property rather than slotted children. Each entry is either a plain `src` string or a `{ src, alt, caption }` object, and the two forms mix freely — captions render below the image and alt text carries through to the rendered `<img>`. A monospace counter in the top bar shows the current position, and prev/next arrow buttons (or the arrow keys) step through the gallery, wrapping at both ends.
Zoom is deliberately a single level: press `+`, click the zoom button, or double-click the image to magnify to 2x, then drag to pan around it. Navigating to another image or closing the viewer resets the zoom. The component fires `arc-change` with the new index on every navigation, and `arc-close` is cancelable, so a consumer can veto a dismissal in progress.Guidelines
When to use
- Use Lightbox for photo galleries, screenshots, and any image worth inspecting at full size
- Open it from a visible thumbnail with `show(index)` so the viewer starts on the image the user chose
- Provide `alt` text for every entry — it also labels the dialog for screen readers
- Use `caption` for attribution or context that should travel with the image
- Listen for `arc-change` when something outside the viewer should track the current image
When not to use
- Do not use Lightbox for non-image content — Modal is the general-purpose overlay
- Do not open it on page load; a full-screen takeover should always be the user's choice
- Do not pass tiny thumbnails as the `src` — supply full-resolution sources, since the whole point is a closer look
- Do not mix it with a second overlay at once; close one surface before opening another
Features
- Full-screen overlay with backdrop blur, sharing the focus-trap and scroll-lock infrastructure used by Modal and Sheet
- Accepts plain `src` strings or `{ src, alt, caption }` objects in the same `images` array
- Prev/next arrow buttons and arrow-key navigation, wrapping at both ends
- Single-level 2x zoom via the `+`/`-` keys, the zoom button, or a double-click, with drag-to-pan while zoomed
- Monospace `3 / 12` position counter with a live region for screen readers
- Caption rendered below the image when an entry provides one
- Escape and backdrop click dismiss; `arc-close` is cancelable for veto
- Fires `arc-change` with the new index on `detail.value` on every navigation
- Focus is trapped while open and restored to the trigger element on close
Preview
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<img id="thumb" src="/photos/valley-thumb.jpg" alt="River valley" />
<arc-lightbox id="viewer"></arc-lightbox>
<script>
const viewer = document.querySelector('#viewer');
viewer.images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
document.querySelector('#thumb').addEventListener('click', () => viewer.show(0));
</script> import { Lightbox } from '@arclux/arc-ui-react';
import { useState } from 'react';
const images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
function Gallery() {
const [open, setOpen] = useState(false);
return (
<>
<img src="/photos/valley-thumb.jpg" alt="River valley" onClick={() => setOpen(true)} />
<Lightbox images={images} open={open} onArcClose={() => setOpen(false)} />
</>
);
} <script setup>
import { ref } from 'vue';
import { Lightbox } from '@arclux/arc-ui-vue';
const open = ref(false);
const images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
</script>
<template>
<img src="/photos/valley-thumb.jpg" alt="River valley" @click="open = true" />
<Lightbox :images="images" :open="open" @arc-close="open = false" />
</template> <script>
import { Lightbox } from '@arclux/arc-ui-svelte';
let open = $state(false);
const images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
</script>
<img src="/photos/valley-thumb.jpg" alt="River valley" onclick={() => open = true} />
<Lightbox {images} {open} on:arc-close={() => open = false} /> import { Component } from '@angular/core';
import { Lightbox } from '@arclux/arc-ui-angular';
@Component({
imports: [Lightbox],
template: `
<img src="/photos/valley-thumb.jpg" alt="River valley" (click)="open = true" />
<arc-lightbox [images]="images" [open]="open" (arcClose)="open = false"></arc-lightbox>
`,
})
export class GalleryComponent {
open = false;
images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
} import { createSignal } from 'solid-js';
import { Lightbox } from '@arclux/arc-ui-solid';
const images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
function Gallery() {
const [open, setOpen] = createSignal(false);
return (
<>
<img src="/photos/valley-thumb.jpg" alt="River valley" onClick={() => setOpen(true)} />
<Lightbox images={images} open={open()} onArcClose={() => setOpen(false)} />
</>
);
} import { useState } from 'preact/hooks';
import { Lightbox } from '@arclux/arc-ui-preact';
const images = [
{ src: '/photos/valley.jpg', alt: 'River valley', caption: 'A river valley in evening light' },
{ src: '/photos/slope.jpg', alt: 'Mountain slope' },
'/photos/canyon.jpg',
];
function Gallery() {
const [open, setOpen] = useState(false);
return (
<>
<img src="/photos/valley-thumb.jpg" alt="River valley" onClick={() => setOpen(true)} />
<Lightbox images={images} open={open} onArcClose={() => setOpen(false)} />
</>
);
} API
-
imagesArray[] - The gallery to display. Each entry is either a `src` string or an object of shape `{ src, alt, caption }`; `alt` and `caption` are optional. Set as a property — arrays do not round-trip through attributes.
-
indexnumber0 - Index of the image currently displayed. Navigation wraps at both ends, so setting it out of range shows the nearest valid image.
-
openbooleanfalse - Controls the visible state of the viewer. Set to `true` to open at the current `index` and activate the focus trap; set to `false` to close and restore focus to the previously-focused element.
Events
-
arc-changedetail: {value: number, index: number} - Fired when the displayed image changes. `detail.value` is the new index.
-
arc-close - Fired when the lightbox closes. Cancelable: call `preventDefault()` to veto the close.
-
arc-open - Fired when the lightbox opens
See Also
- Carousel A scrollable slide container with navigation arrows, dot indicators, auto-play, looping, and keyboard controls.
- Image Enhanced image component with shimmer loading skeleton, smooth fade-in transition, error fallback, and aspect ratio presets.
- Modal General-purpose focus-trapping overlay with backdrop blur, slide-up animation, and ESC-to-close behavior for forms, settings, and rich content that needs full user attention.