To source

a-lightbox

A slot-based image lightbox element with built-in overlay behavior and shared image transitions via the View Transitions API.

The a-lightbox element turns a trigger image into a modal image viewer. It owns the overlay state, scroll locking, focus management, Escape handling, and the transition between the trigger image and the enlarged image.

Forest path between tall trees
<a-lightbox>
  <button slot="trigger" type="button">
    <img src="/images/thumb.jpg" alt="Gallery preview" />
  </button>

  <div slot="content">
    <img src="/images/large.jpg" alt="Gallery preview" />
  </div>

  <button slot="close" type="button">
    Close
  </button>
</a-lightbox>

The element requires an <img> in the trigger slot and an <img> in the content slot. It uses those two images as the shared transition endpoints.

Accessibility features

  • Focus moves into the lightbox when it opens and returns to the previously focused element when it closes.
  • Pressing Escape closes the overlay.
  • The overlay uses role="dialog" and aria-modal="true".
  • The trigger receives aria-haspopup="dialog" and an updated aria-expanded state.
  • The trigger image and enlarged image should use meaningful alt text when the image content is important.

How to use it with examples

Programmatic control

import "@sv/elements/lightbox";

const lightbox = document.querySelector("a-lightbox");

await lightbox.show();
await lightbox.hide();
lightbox.toggle();

Styling slotted content

[slot="content"] img {
  max-width: 96vw;
  max-height: 96vh;
  object-fit: contain;
}

[slot="close"] button {
  border-radius: 0.5rem;
  background: rgb(255 255 255 / 0.9);
  padding: 0.5rem 0.75rem;
}

Using custom close content

<a-lightbox>
  <button slot="trigger" type="button">
    <img src="/thumb.jpg" alt="Preview" />
  </button>

  <div slot="content">
    <img src="/large.jpg" alt="Preview" />
  </div>

  <div slot="close">
    <button type="button" aria-label="Close image viewer">
      <svg viewBox="0 0 24 24" aria-hidden="true"><!-- icon --></svg>
    </button>
  </div>
</a-lightbox>

Customization options

  • Use the trigger, content, and close slots to provide your own markup.
  • Style the trigger, content, and close markup directly in the nodes you pass into those slots.
  • Call show(), hide(), or toggle() for programmatic control.
  • The element requires document.startViewTransition(). It throws instead of falling back when the API is unavailable.

Type Documentation

Lightbox

Attributes


Name Type Default value Description

Methods


Lightbox.bindTriggerClickListeners()

src/Lightbox.ts:312

Lightbox.clearTransitionNames(triggerImage: HTMLImageElement, contentImage: HTMLImageElement, finished: Promise)

src/Lightbox.ts:380

Lightbox.firstUpdated()

src/Lightbox.ts:112

Invoked when the element is first updated. Implement to perform one time work on the element after update.

firstUpdated() {
  this.renderRoot.getElementById('my-text-area').focus();
}

Setting properties inside this method will trigger the element to update again after this update cycle completes.

Lightbox.hide()

src/Lightbox.ts:275

Lightbox.matchesAssignedPath(path: EventTarget[], elements: Element[])

src/Lightbox.ts:355

Lightbox.moveElements(elements: Element[], mount: undefined | Element, label: string)

src/Lightbox.ts:323

Lightbox.onBlurExit(event: Event)

src/Lightbox.ts:160

Lightbox.onStageClick(event: MouseEvent)

src/Lightbox.ts:169

Lightbox.onTriggerSlotChange()

src/Lightbox.ts:155

Lightbox.prepareTransition()

src/Lightbox.ts:434

Lightbox.render()

src/Lightbox.ts:131

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's

  • typically a

. Setting properties inside this method will not trigger the element to update.

Lightbox.requireBlur()

src/Lightbox.ts:372

Lightbox.requireImage(elements: Element[], slot: string)

src/Lightbox.ts:340

Lightbox.requireStartViewTransition()

src/Lightbox.ts:364

Lightbox.restoreElements(elements: Element[], slot: string)

src/Lightbox.ts:333

Lightbox.restoreStructure()

src/Lightbox.ts:231

Lightbox.runHide()

src/Lightbox.ts:279

Lightbox.runShow()

src/Lightbox.ts:247

Lightbox.runTransition(target: boolean, transition: () => Promise)

src/Lightbox.ts:403

Lightbox.show()

src/Lightbox.ts:243

Lightbox.swapTransitionNames(from: HTMLImageElement, to: HTMLImageElement)

src/Lightbox.ts:398

Lightbox.syncStructure()

src/Lightbox.ts:214

Lightbox.syncTriggerAttributes()

src/Lightbox.ts:236

Lightbox.toggle()

src/Lightbox.ts:303

Lightbox.updated(changed: Map)

src/Lightbox.ts:123

Invoked whenever the element is updated. Implement to perform post-updating tasks via DOM APIs, for example, focusing an element.

Setting properties inside this method will trigger the element to update again after this update cycle completes.

Lightbox.waitForImageReady(image: HTMLImageElement)

src/Lightbox.ts:470

Lightbox.waitForPortal()

src/Lightbox.ts:454

References