Lightbox
Preview Available in release assets
Enhance full-size image links with a native modal viewer.
Lightbox primary example
<p><a href="product-large.jpg" data-lightbox-open="product-lightbox" data-media-index="0">Open full-size product image</a></p>
<dialog class="thin-dialog" id="product-lightbox" data-lightbox aria-labelledby="lightbox-title">
<form method="dialog">
<button class="thin-button" data-variant="secondary">Close</button>
</form>
<h2 id="lightbox-title">Product images</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="product-large.jpg" alt="Canvas tote, front view">
<span data-image-fallback>Image unavailable. Close this viewer to use the original image link.</span>
</figure>
</div>
<div data-media-controls>
<button class="thin-button" data-variant="secondary" type="button" data-lightbox-zoom aria-pressed="false">
<svg class="thin-icon" data-icon="zoom-in" viewBox="0 0 24 24" aria-hidden="true">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3M11 8v6M8 11h6" />
</svg>
<span>Zoom</span>
</button>
<output data-media-status>Image 1 of 1</output>
</div>
</dialog>Show code
<p><a href="product-large.jpg" data-lightbox-open="product-lightbox" data-media-index="0">Open full-size product image</a></p>
<dialog class="thin-dialog" id="product-lightbox" data-lightbox aria-labelledby="lightbox-title">
<form method="dialog">
<button class="thin-button" data-variant="secondary">Close</button>
</form>
<h2 id="lightbox-title">Product images</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="product-large.jpg" alt="Canvas tote, front view">
<span data-image-fallback>Image unavailable. Close this viewer to use the original image link.</span>
</figure>
</div>
<div data-media-controls>
<button class="thin-button" data-variant="secondary" type="button" data-lightbox-zoom aria-pressed="false">
<svg class="thin-icon" data-icon="zoom-in" viewBox="0 0 24 24" aria-hidden="true">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3M11 8v6M8 11h6" />
</svg>
<span>Zoom</span>
</button>
<output data-media-status>Image 1 of 1</output>
</div>
</dialog>Variant gallery
Each authored example uses the production assets and includes copyable markup.
Single-image native viewer
An ordinary full-size illustration link opens a named native modal only after explicit enhancement. Close or Escape returns focus to the original link; without JavaScript the link opens the SVG directly.
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-single" data-media-index="0">Open illustration 1</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-single" data-lightbox aria-labelledby="lightbox-single-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-single-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<output data-media-status>Image 1 of 1</output>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Show code
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-single" data-media-index="0">Open illustration 1</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-single" data-lightbox aria-labelledby="lightbox-single-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-single-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<output data-media-status>Image 1 of 1</output>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Gallery with direct image destinations
Open any of the three images. Previous/Next or Left/Right move between authored media; only the current figure is displayed inside the viewer.
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-gallery" data-media-index="0">Open illustration 1</a></li>
<li><a href="/examples/media/back.svg" data-lightbox-open="lightbox-gallery" data-media-index="1">Open illustration 2</a></li>
<li><a href="/examples/media/detail.svg" data-lightbox-open="lightbox-gallery" data-media-index="2">Open illustration 3</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-gallery" data-lightbox aria-labelledby="lightbox-gallery-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-gallery-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/back.svg" alt="Canvas tote illustration 2">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/back.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/detail.svg" alt="Canvas tote illustration 3">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/detail.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<div data-media-controls>
<button class="thin-button" type="button" data-media-previous>Previous image</button>
<button class="thin-button" type="button" data-media-next>Next image</button>
<output data-media-status>Image 1</output>
</div>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Show code
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-gallery" data-media-index="0">Open illustration 1</a></li>
<li><a href="/examples/media/back.svg" data-lightbox-open="lightbox-gallery" data-media-index="1">Open illustration 2</a></li>
<li><a href="/examples/media/detail.svg" data-lightbox-open="lightbox-gallery" data-media-index="2">Open illustration 3</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-gallery" data-lightbox aria-labelledby="lightbox-gallery-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-gallery-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/back.svg" alt="Canvas tote illustration 2">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/back.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/detail.svg" alt="Canvas tote illustration 3">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/detail.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<div data-media-controls>
<button class="thin-button" type="button" data-media-previous>Previous image</button>
<button class="thin-button" type="button" data-media-next>Next image</button>
<output data-media-status>Image 1</output>
</div>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Anatomy
- Original image link
- Native dialog
- Named stage
- Close and zoom controls
Variants and sizes
- Single image — shown above
- Gallery — shown above
States and difficult content
Rendered fixtures exercise authored content and constrained layouts with the same production assets.
Closed, open and zoomed viewer
Starts closed so the initial state is a real native modal transition. Open a link, activate Zoom image, then close or press Escape. Enlarged content scrolls within the stage instead of widening the page.
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-states" data-media-index="0">Open illustration 1</a></li>
<li><a href="/examples/media/back.svg" data-lightbox-open="lightbox-states" data-media-index="1">Open illustration 2</a></li>
<li><a href="/examples/media/detail.svg" data-lightbox-open="lightbox-states" data-media-index="2">Open illustration 3</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-states" data-lightbox aria-labelledby="lightbox-states-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-states-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/back.svg" alt="Canvas tote illustration 2">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/back.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/detail.svg" alt="Canvas tote illustration 3">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/detail.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<div data-media-controls>
<button class="thin-button" type="button" data-media-previous>Previous image</button>
<button class="thin-button" type="button" data-media-next>Next image</button>
<output data-media-status>Image 1</output>
</div>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Show code
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-states" data-media-index="0">Open illustration 1</a></li>
<li><a href="/examples/media/back.svg" data-lightbox-open="lightbox-states" data-media-index="1">Open illustration 2</a></li>
<li><a href="/examples/media/detail.svg" data-lightbox-open="lightbox-states" data-media-index="2">Open illustration 3</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-states" data-lightbox aria-labelledby="lightbox-states-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-states-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item>
<img src="/examples/media/front.svg" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/back.svg" alt="Canvas tote illustration 2">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/back.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/detail.svg" alt="Canvas tote illustration 3">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/detail.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<div data-media-controls>
<button class="thin-button" type="button" data-media-previous>Previous image</button>
<button class="thin-button" type="button" data-media-next>Next image</button>
<output data-media-status>Image 1</output>
</div>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>Unavailable preview with native escape path
Open the first illustration to inspect a failed-preview snapshot. The original SVG destination and native Close control remain usable. Browser checks separately exercise a newly failing image.
Show code
<section style="overflow-wrap: anywhere">
<ul>
<li><a href="/examples/media/front.svg" data-lightbox-open="lightbox-failed" data-media-index="0">Open illustration 1</a></li>
<li><a href="/examples/media/back.svg" data-lightbox-open="lightbox-failed" data-media-index="1">Open illustration 2</a></li>
<li><a href="/examples/media/detail.svg" data-lightbox-open="lightbox-failed" data-media-index="2">Open illustration 3</a></li>
</ul>
<dialog class="thin-dialog" id="lightbox-failed" data-lightbox aria-labelledby="lightbox-failed-title">
<form method="dialog">
<button class="thin-button">Close viewer</button>
</form>
<h2 id="lightbox-failed-title">Canvas tote illustrations</h2>
<div data-lightbox-stage>
<figure data-media-item data-image-error>
<img src="data:image/png;base64,broken" alt="Canvas tote illustration 1">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/front.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/back.svg" alt="Canvas tote illustration 2">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/back.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
<figure data-media-item>
<img src="/examples/media/detail.svg" alt="Canvas tote illustration 3">
<span data-image-fallback>Preview unavailable. <a href="/examples/media/detail.svg">Open the original illustration</a>, or close this viewer.</span>
</figure>
</div>
<button class="thin-button" type="button" data-lightbox-zoom aria-pressed="false">Zoom image</button>
<div data-media-controls>
<button class="thin-button" type="button" data-media-previous>Previous image</button>
<button class="thin-button" type="button" data-media-next>Next image</button>
<output data-media-status>Image 1</output>
</div>
</dialog>
</section>
<script type="module">import { enhanceMedia } from "/behaviors.js"; enhanceMedia(document);</script>- Closed — shown above
- Open — shown above
- Zoomed — shown above
- Image failure — shown above
Interaction and keyboard behavior
The original href works without JavaScript; enhancement opens a dialog, supports arrow navigation, and restores focus on close.
Accessibility
Use a labelled native dialog, meaningful image alternatives, real buttons, and an original destination link.
- Contract
DIALOG- Basis
- Native <dialog> and image/link fallback; no lightbox-specific APG role
- Behavior guarantees
- Uses native <dialog> and method="dialog"; the trigger helper only coordinates opening, initial focus, and return focus.
- Rejects ambiguous or unnamed targets and keeps the authored link fallback when modal presentation is unavailable.
- Focuses an available control on open and restores a connected trigger after close.
- Clamps the media position and resets zoom.
- Evidence
tests/unit/library/media.test.tstests/unit/library/advanced-component-contracts.test.ts
API
Use an anchor with data-lightbox-open pointing to dialog.thin-dialog[data-lightbox].
Behavior tier: dependency-free
Structured host, property, and example tables are not authored for this item yet. Use the summary above and the primary example.
Fallback
Every image remains an ordinary link or a natively scrollable figure without enhancement.
Assets and dependencies
/foundation.css/layouts.css/components.css/behaviors.js
Dependencies: None
Source: packages/ui/src/items/media/style.ts
Composition
Derived from the examples and style specs, not authored.