Skip to content

Feedback

Lightbox

A full-screen viewer for images and videos, single or as a gallery, on a native modal dialog.

<script>
  import { Lightbox } from "@codeatlasdev/ui";

  let open = $state(false);
</script>

<button onclick={() => (open = true)}>View photo</button>
<Lightbox bind:open src={url} alt="Photo sent by Maria" />

Pass items for a gallery of images and videos; src and alt are sugar for a single image.

<Lightbox bind:open bind:index items={[
  { src: photo, alt: "Beach", caption: "Praia", meta: "Maria, 10:42" },
  { type: "video", src: clip, poster, alt: "Short clip" },
]} ondownload={(item, i) => save(item)} />

With more than one item the viewer shows previous and next buttons, a counter, and answers to the ArrowLeft and ArrowRight keys and to a horizontal swipe. It does not wrap: the buttons at either end are aria-disabled and keep focus. Arrow keys are left alone while a video has focus so they keep seeking, and a video is paused as soon as you move to another item. The caption and meta (sender, time) overlay the bottom edge without changing the media box. A Download button appears for galleries: ondownload(item, index) replaces the default <a download> to item.download ?? item.src, which only works for same-origin or CORS-enabled files.

The media is contained in the viewport and respects the device safe areas. Escape, the close button and a click on the backdrop close it. Because it is a native modal <dialog>, the page behind is inert, focus returns to the trigger and scrolling is locked while it is open. alt is required.

#091

Open from a button

Reference #091 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Button, Lightbox } from '@codeatlasdev/ui';

  const photo =
    "data:image/svg+xml;utf8," +
    encodeURIComponent(
      '<svg xmlns="http://www.w3.org/2000/svg" width="640" height="400"><rect width="640" height="400" fill="#334155"/><circle cx="320" cy="200" r="90" fill="#94a3b8"/></svg>'
    );
  let open = $state(false);
</script>

<Button variant="outlined" onclick={() => (open = true)}>View photo</Button>
<Lightbox bind:open src={photo} alt="Gray circle on a dark background" />
#242

Arrow keys, buttons and swipe move through the items.

Reference #242 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Button, Lightbox, type LightboxItem } from '@codeatlasdev/ui';

  const svg = (fill: string, shape: string) =>
    'data:image/svg+xml;utf8,' +
    encodeURIComponent(
      `<svg xmlns="http://www.w3.org/2000/svg" width="640" height="400"><rect width="640" height="400" fill="${fill}"/>${shape}</svg>`
    );

  const items: LightboxItem[] = [
    {
      src: svg('#334155', '<circle cx="320" cy="200" r="90" fill="#94a3b8"/>'),
      alt: 'Gray circle on a dark background',
      caption: 'Moodboard, v1',
      meta: 'Maria, 10:42',
    },
    {
      type: 'video',
      src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4',
      poster: svg('#0f766e', '<polygon points="280,140 280,260 380,200" fill="#99f6e4"/>'),
      alt: 'Flower blooming',
      caption: 'Short clip',
      meta: 'Bruno, 10:44',
    },
    {
      src: svg('#7c2d12', '<rect x="220" y="120" width="200" height="160" fill="#fdba74"/>'),
      alt: 'Orange square on a brown background',
      caption: 'Moodboard, v2',
    },
  ];

  let open = $state(false);
  let index = $state(0);
</script>

<Button variant="outlined" onclick={() => { index = 0; open = true; }}>Open gallery ({items.length})</Button>
<Lightbox bind:open bind:index {items} />

Props

PropTypeDefaultDescription
openbooleanfalseBindable open state.
srcstring–Single-image sugar: same as `items={[{ src, alt }]}`.
altstring–Image description for the `src` form.
itemsLightboxItem[]–Gallery. Each item: `{ type?: 'image' | 'video', src, alt?, caption?, meta?, poster?, download? }`. Wins over `src`.
indexnumber0Bindable current item.
ondownload(item: LightboxItem, index: number) => void–Replaces the default download link. The Download button shows for `items` galleries.
onclose() => void–Called after the viewer closes.