Lightbox Gallery

Gallery whose images open enlarged in an overlay.

html

<div class="lb-gallery">
  <a class="lb-gallery__thumb" href="#lb-photo" style="border-radius:10px;" aria-label="Open enlarged image: Meadow study, no. 3">
    <svg viewBox="0 0 120 90" width="100%" height="100%" role="img" aria-hidden="true"><rect width="120" height="90" fill="#BFD9F2"/><circle cx="60" cy="45" r="22" fill="#A8E6C1"/></svg>
  </a>
  <div class="lb-gallery__overlay lb-gallery__overlay--dim" id="lb-photo" role="dialog" aria-modal="true" aria-label="Meadow study, no. 3">
    <a class="lb-gallery__close" href="#" aria-label="Close enlarged image" style="background:#D9C8F0;">&times;</a>
    <figure class="lb-gallery__figure">
      <svg viewBox="0 0 400 260" width="100%" height="100%" role="img" aria-hidden="true"><rect width="400" height="260" fill="#241430"/><circle cx="200" cy="130" r="70" fill="#D9C8F0"/></svg>
      <figcaption class="lb-gallery__caption">Meadow study, no. 3</figcaption>
    </figure>
  </div>
</div>
<style>
.lb-gallery { max-width: 200px; font: 13px/1.4 system-ui, sans-serif; color: #241430; }
.lb-gallery__thumb { display: block; overflow: hidden; border: 1px solid #24143022; }
.lb-gallery__overlay { position: fixed; inset: 0; display: none; align-items: center; justify-content: center; background: #24143099; z-index: 50; }
.lb-gallery__overlay--dim { background: #241430e6; }
.lb-gallery__overlay:target { display: flex; }
.lb-gallery__close { position: absolute; top: 16px; right: 16px; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #241430; text-decoration: none; font-size: 20px; line-height: 1; }
.lb-gallery__close:focus-visible { outline: 2px solid #FAF7F2; outline-offset: 2px; }
.lb-gallery__figure { margin: 0; max-width: 360px; width: 90%; }
.lb-gallery__figure svg { display: block; border-radius: 8px; }
.lb-gallery__caption { margin-top: 8px; color: #FAF7F2; text-align: center; }
</style>

tailwind

<div class="lb-gallery-tw max-w-[200px] font-sans text-[13px] text-[#241430]">
  <a class="block overflow-hidden border border-[#24143022]" href="#lb-photo-tw" style="border-radius:10px;" aria-label="Open enlarged image: Meadow study, no. 3">
    <svg viewBox="0 0 120 90" width="100%" height="100%" role="img" aria-hidden="true"><rect width="120" height="90" fill="#BFD9F2"/><circle cx="60" cy="45" r="22" fill="#A8E6C1"/></svg>
  </a>
  <div class="lb-gallery-tw__overlay lb-gallery-tw__overlay--dim fixed inset-0 hidden items-center justify-center z-50" id="lb-photo-tw" role="dialog" aria-modal="true" aria-label="Meadow study, no. 3">
    <a class="absolute top-4 right-4 w-8 h-8 rounded-full flex items-center justify-center text-[#241430] no-underline text-xl leading-none" href="#" aria-label="Close enlarged image" style="background:#D9C8F0;">&times;</a>
    <figure class="m-0 max-w-[360px] w-[90%]">
      <svg viewBox="0 0 400 260" width="100%" height="100%" role="img" aria-hidden="true" class="block rounded-lg"><rect width="400" height="260" fill="#241430"/><circle cx="200" cy="130" r="70" fill="#D9C8F0"/></svg>
      <figcaption class="mt-2 text-center text-[#FAF7F2]">Meadow study, no. 3</figcaption>
    </figure>
  </div>
</div>
<style>
.lb-gallery-tw__overlay { background: #24143099; }
.lb-gallery-tw__overlay--dim { background: #241430e6; }
.lb-gallery-tw__overlay:target { display: flex !important; }
</style>

react

export function LightboxGallery({
  caption = "Meadow study, no. 3",
  accent = "#D9C8F0",
  radius = 10,
  dimmed = true,
}) {
  return (
    <div style={{ maxWidth: 200, font: "13px/1.4 system-ui, sans-serif", color: "#241430" }}>
      <a href="#lb-photo-react" aria-label={`Open enlarged image: ${caption}`}
        style={{ display: "block", overflow: "hidden", border: "1px solid #24143022", borderRadius: radius }}>
        <svg viewBox="0 0 120 90" width="100%" height="100%" role="img" aria-hidden="true"><rect width="120" height="90" fill="#BFD9F2" /><circle cx="60" cy="45" r="22" fill="#A8E6C1" /></svg>
      </a>
      <div id="lb-photo-react" role="dialog" aria-modal="true" aria-label={caption}
        style={{ position: "fixed", inset: 0, display: "none", alignItems: "center", justifyContent: "center",
          background: dimmed ? "#241430e6" : "#24143099", zIndex: 50 }}>
        <a href="#" aria-label="Close enlarged image"
          style={{ position: "absolute", top: 16, right: 16, width: 32, height: 32, borderRadius: "50%",
            display: "flex", alignItems: "center", justifyContent: "center", color: "#241430",
            textDecoration: "none", fontSize: 20, lineHeight: 1, background: accent }}>
          &times;
        </a>
        <figure style={{ margin: 0, maxWidth: 360, width: "90%" }}>
          <svg viewBox="0 0 400 260" width="100%" height="100%" role="img" aria-hidden="true" style={{ display: "block", borderRadius: 8 }}><rect width="400" height="260" fill="#241430" /><circle cx="200" cy="130" r="70" fill={accent} /></svg>
          <figcaption style={{ marginTop: 8, color: "#FAF7F2", textAlign: "center" }}>{caption}</figcaption>
        </figure>
      </div>
      {/* :target only works with static anchors; in React, drive the dialog's open state from props/state instead. */}
    </div>
  );
}