Component Library

← Back to gallery

Lightbox figure

Category: Overlays · Tags: lightbox, image, figure, dialog, zoom

Harbour at dusk, illustration.
Two sailing boats moored in a harbour under an orange evening sky
Harbour at dusk. Two boats wait for the morning tide.

How to use it

Use when a small image in an article or product page needs a closer look without leaving the page. Do not use it for galleries that need next/previous navigation or for images that carry text people must read (show those at full size inline). After copying, replace both SVG drawings (or swap in an <img> with real alt text and a data: or local src), update the <title> and captions, and keep the ids unique.

Accessibility

The thumbnail is a native <button> whose visible text says what it does, and the large view is a native <dialog> opened with showModal(), so focus moves inside, the page behind is inert and Escape closes it. The large drawing is an <svg role="img"> named by its <title>, the dialog is named by its <figcaption> through aria-labelledby, and closing it (Close, Escape or a click outside) returns focus to the thumbnail. Caption text is #334155 on #ffffff (10.35:1), the button label #1e40af on #ffffff (8.72:1) and the Close button white on #0f172a (17.85:1).

Source (copy-ready)

<div class="dcl-lightbox-figure">
  <figure class="dcl-lightbox-figure__figure">
    <button type="button" class="dcl-lightbox-figure__thumb" aria-haspopup="dialog">
      <svg class="dcl-lightbox-figure__art" viewBox="0 0 120 80" aria-hidden="true" focusable="false"><rect width="120" height="80" fill="#fdba74"/><circle cx="92" cy="26" r="10" fill="#fef3c7"/><rect y="52" width="120" height="28" fill="#1e3a8a"/><path d="M20 52 L40 52 L36 60 L24 60 Z" fill="#0f172a"/><path d="M30 52 L30 30 L42 50 Z" fill="#ffffff"/><path d="M66 52 L92 52 L88 61 L70 61 Z" fill="#0f172a"/><path d="M78 52 L78 24 L94 50 Z" fill="#ffffff"/></svg>
      <span class="dcl-lightbox-figure__hint">View larger image</span>
    </button>
    <figcaption class="dcl-lightbox-figure__caption">Harbour at dusk, illustration.</figcaption>
  </figure>
  <dialog class="dcl-lightbox-figure__dialog" aria-labelledby="dcl-lightbox-figure-caption">
    <figure class="dcl-lightbox-figure__large">
      <svg class="dcl-lightbox-figure__art" viewBox="0 0 120 80" role="img" aria-labelledby="dcl-lightbox-figure-alt"><title id="dcl-lightbox-figure-alt">Two sailing boats moored in a harbour under an orange evening sky</title><rect width="120" height="80" fill="#fdba74"/><circle cx="92" cy="26" r="10" fill="#fef3c7"/><rect y="52" width="120" height="28" fill="#1e3a8a"/><path d="M20 52 L40 52 L36 60 L24 60 Z" fill="#0f172a"/><path d="M30 52 L30 30 L42 50 Z" fill="#ffffff"/><path d="M66 52 L92 52 L88 61 L70 61 Z" fill="#0f172a"/><path d="M78 52 L78 24 L94 50 Z" fill="#ffffff"/></svg>
      <figcaption class="dcl-lightbox-figure__caption" id="dcl-lightbox-figure-caption">Harbour at dusk. Two boats wait for the morning tide.</figcaption>
    </figure>
    <form method="dialog" class="dcl-lightbox-figure__form">
      <button type="submit" class="dcl-lightbox-figure__close">Close</button>
    </form>
  </dialog>
</div>
<style>
.dcl-lightbox-figure { font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-lightbox-figure__figure { margin: 0; max-width: 14rem; }
.dcl-lightbox-figure__thumb { display: block; width: 100%; padding: 0.35rem; border: 1px solid #94a3b8; border-radius: 8px; cursor: zoom-in; font: inherit; color: #1e40af; background-color: #ffffff; }
.dcl-lightbox-figure__thumb:hover { color: #1e40af; background-color: #f1f5f9; }
.dcl-lightbox-figure__thumb:focus-visible, .dcl-lightbox-figure__close:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
.dcl-lightbox-figure__art { display: block; width: 100%; height: auto; border-radius: 4px; }
.dcl-lightbox-figure__hint { display: block; padding-top: 0.35rem; font-weight: 600; text-decoration: underline; }
.dcl-lightbox-figure__caption { margin-top: 0.4rem; font-size: 0.9rem; color: #334155; background-color: #ffffff; }
.dcl-lightbox-figure__dialog { width: 36rem; max-width: calc(100vw - 2rem); box-sizing: border-box; padding: 1rem; border: none; border-radius: 10px; color: #0f172a; background-color: #ffffff; }
.dcl-lightbox-figure__large { margin: 0; }
.dcl-lightbox-figure__form { display: flex; justify-content: flex-end; margin-top: 0.75rem; }
.dcl-lightbox-figure__close { font: inherit; font-weight: 600; padding: 0.5rem 1rem; border: 1px solid #0f172a; border-radius: 6px; cursor: pointer; color: #ffffff; background-color: #0f172a; }
.dcl-lightbox-figure__close:hover { color: #ffffff; background-color: #334155; }
</style>
<script>
(function () {
  document.querySelectorAll(".dcl-lightbox-figure").forEach(function (root) {
    if (root.dataset.dclBound) { return; }
    root.dataset.dclBound = "true";
    var thumb = root.querySelector(".dcl-lightbox-figure__thumb");
    var dialog = root.querySelector(".dcl-lightbox-figure__dialog");
    if (!thumb || !dialog || typeof dialog.showModal !== "function") { return; }
    thumb.addEventListener("click", function () { if (!dialog.open) { dialog.showModal(); } });
    dialog.addEventListener("click", function (event) {
      var box = dialog.getBoundingClientRect();
      var outside = event.clientX < box.left || event.clientX > box.right || event.clientY < box.top || event.clientY > box.bottom;
      if (outside && event.target === dialog) { dialog.close(); }
    });
    dialog.addEventListener("close", function () { thumb.focus(); });
  });
})();
</script>

Was this useful? Send feedback.