Overlay · astro-ui · Lightbox

LightboxJS

Accessible image/video/iframe gallery overlay with arrows, counter, and indicators.

Lightbox is an accessible image, video, and iframe gallery overlay. It is built on the native <dialog> element, so modality, focus containment, Escape, and focus return all come from the platform, while one scoped inline script ships with the component to drive the gallery: prev/next arrows, keyboard arrows, indicator dots, a live counter, and cross-instance group sync. Opening needs a single app-level showModal() call; items are LightboxItem children whose media type (image, video, iframe) is inferred from the source URL and overridable per item.

Features

  • Native <dialog>: focus containment, Escape, focus return
  • Prev/next arrows, keyboard arrows, indicator dots
  • Live "1 / 5" counter with aria-live announcements
  • Group sync: several lightboxes share one active index
  • LightboxItem auto-detects image / video / iframe media
  • Backdrop click, × button, and Esc close with zero extra code

Usage

---
import { Button, Lightbox, LightboxItem } from "astro-ui";
---

<Button id="open-gallery">View gallery</Button>
<Lightbox id="gallery" showCounter indicators>
  <LightboxItem src="/img/a.jpg" alt="Sunset" caption="Beach sunset" />
  <LightboxItem src="/img/b.jpg" alt="Trail" caption="Summit view" />
  <h2 slot="title">Photo gallery</h2>
  <p slot="description">Use ← → arrows or swipe to navigate.</p>
</Lightbox>
<script>
  document.getElementById("open-gallery")?.addEventListener("click", () =>
    document.getElementById("aui-lightbox-gallery")?.showModal());
</script>

Demos

Programmatic control

The remote buttons dispatch lightbox:set events; they enable once the dialog is open.

Slide one

Step 1

Slide two

Step 2

Slide three

Step 3

<Button id="open-tour">Open at slide 2</Button>

<Lightbox id="tour" ariaLabel="Product tour">
  <LightboxItem src="/demo/lightbox/aurora.svg" alt="Slide one" caption="Step 1" />
  <LightboxItem src="/demo/lightbox/dunes.svg" alt="Slide two" caption="Step 2" />
  <LightboxItem src="/demo/lightbox/metro.svg" alt="Slide three" caption="Step 3" />
</Lightbox>

<script>
  const tour = document.getElementById("aui-lightbox-tour");
  document.getElementById("open-tour")?.addEventListener("click", () => {
    tour?.showModal();
    // Open on a specific slide…
    tour?.dispatchEvent(new CustomEvent("lightbox:set", {detail: {index: 1}}));
    // …or step remotely: dispatch({action: "next"} / {action: "prev"}).
  });
</script>

Thumbnail trigger

Click an image to inspect it full size.

Aurora over mountains

Aurora borealis

Long exposure, Tromsø.

Desert dunes

Dunes at dusk

Metro platform

Night transit

<Lightbox id="preview" ariaLabel="Image preview">
  <LightboxItem src="/demo/lightbox/aurora.svg" alt="Aurora over mountains" caption="Aurora borealis" />
  <LightboxItem src="/demo/lightbox/dunes.svg" alt="Desert dunes" caption="Dunes at dusk" />
  <LightboxItem src="/demo/lightbox/metro.svg" alt="Metro platform" caption="Night transit" />
</Lightbox>

<!-- Thumbnails: clicking one opens the lightbox on that image, full size -->
<div class="thumbs">
  <button data-thumb="0" aria-label="Open: Aurora borealis">
    <img src="/demo/lightbox/aurora.svg" alt="" />
  </button>
  <button data-thumb="1" aria-label="Open: Dunes at dusk">
    <img src="/demo/lightbox/dunes.svg" alt="" />
  </button>
  <button data-thumb="2" aria-label="Open: Night transit">
    <img src="/demo/lightbox/metro.svg" alt="" />
  </button>
</div>

<script>
  const lb = document.getElementById("aui-lightbox-preview");
  document.querySelectorAll("[data-thumb]").forEach((btn) => {
    btn.addEventListener("click", () => {
      lb?.showModal();
      lb?.dispatchEvent(
        new CustomEvent("lightbox:set", {detail: {index: Number(btn.dataset.thumb)}}),
      );
    });
  });
</script>

API

Props

PropTypeDefaultDescription
idstringrequiredDialog DOM id (`aui-lightbox-<id>`) and aria target ids.
groupstring—Links several Lightbox instances into one synchronized gallery.
navigationbooleantruePrev/next buttons.
showClosebooleantrueNative × close button.
showCounterbooleanfalseShows the live "1 / 5" counter.
counterLabelstring"Image"Counter word, e.g. "Photo" → "Photo 1 of 3".
indicatorsbooleanfalseOne clickable dot per item.
allowAutoplaybooleanfalseAuto-plays videos when they become active.
durationnumber400Gallery scroll transition duration in ms.
keyboardbooleantrueArrowLeft/ArrowRight navigation.
classstring—Merged via cn().

Slots

SlotDescription
defaultLightboxItem gallery items.
titleDialog heading (wired to aria-labelledby).
descriptionHelper text (wired to aria-describedby).
countCustom counter total (auto-filled from item count).

Accessibility

Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.

  • Native <dialog> semantics: modal focus containment, Escape-to-close, focus return
  • Inactive slides get aria-hidden; slides carry aria-roledescription="slide"
  • Counter is aria-live="polite" so index changes are announced
  • Indicator dots are role="tab" inside a role="tablist"
  • prefers-reduced-motion disables smooth gallery scrolling

FAQ

How do I open it?

The component ships no opener by design: call document.getElementById('aui-lightbox-<id>').showModal() from your own button. This keeps the trigger fully under app control.

How does media type detection work?

LightboxItem infers image (jpg/png/webp/avif/gif/svg), video (mp4/webm/ogv/mov), or iframe (html/php, YouTube/Vimeo URLs) from the src, and accepts an explicit type override.

Can two lightboxes stay in sync?

Yes — give them the same group name; advancing one updates the other's active index, useful for thumbnail + main-view layouts.

Changelog

Version history mentioning Lightbox.

v0.1.0 — 2026-11-11
added
  • Overlay (8): Dialog, AlertDialog, Sheet, Tooltip, Popover, HoverCard, Lightbox, Menu.
fixed
  • Dialog, Lightbox, Sheet, and AlertDialog backdrops, Progress stripes, Carousel shadows, and Chart SVG shadows resolve through tokens instead of hard-coded colors.