<light-box>
<ul>
<li>
<a href="https://images.unsplash.com/photo-1493548578639-b0c241186eb0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDJ8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=1920"><img src='https://images.unsplash.com/photo-1493548578639-b0c241186eb0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDJ8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=400' alt='a cat asleep'></a>
</li>
<li>
<a href="https://images.unsplash.com/photo-1498336179775-9836baef8fdf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDF8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=1920"><img src="https://images.unsplash.com/photo-1498336179775-9836baef8fdf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDF8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=400" alt="a kitten asleep on its back"></a>
</li>
<li>
<a href="https://images.unsplash.com/photo-1445499348736-29b6cdfc03b9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDR8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=1920"><img src="https://images.unsplash.com/photo-1445499348736-29b6cdfc03b9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wyMDcwNnwwfDF8c2VhcmNofDR8fGtpdHRlbnxlbnwwfHx8fDE3MjM1ODExMjR8MA&ixlib=rb-4.0.3&q=80&w=400" alt="a kitten looking past the camera"></a>
</li>
</ul>
</light-box>
ul {
list-style: none;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
img {
width: 100%;
}
class LightBox extends HTMLElement {
#lightBoxes;
constructor() {
super();
this.#lightBoxes = new Map();
const style = document.createElement("style");
style.textContent = `
:where(light-box>dialog>img){
max-width: 100%;
}
:where(light-box>dialog>form){
display:flex;
place-content: center;
}
:where(light-box>dialog:has(img):first-of-type button[value="prev"]){
display:none;
}
:where(light-box>dialog:has(img):last-of-type button[value="next"]){
display:none;
}
:where(light-box>dialog)::backdrop{
background-color: rgba(0,0,0,0.25);
-webkit-backdrop-filter: blur(0.25rem);
backdrop-filter: blur(0.25rem);
}`;
this.append(style);
// Define this here for correct `this` context.
this.handleOpenLightBox = (e) => {
e.preventDefault();
const dialog = this.#lightBoxes.get(e.target.closest("a"));
dialog.showModal();
};
this.handleCloseLightBox = (e) => {
console.log(e);
const dialog = e.target;
const value = dialog.returnValue;
let el;
if (value === "next") {
el = dialog.nextElementSibling;
} else if (value === "prev") {
el = dialog.previousElementSibling;
}
if (el instanceof HTMLElement && el.tagName === "DIALOG") {
el.showModal();
}
};
}
createLightBox(el) {
const thumbImage = el.querySelector("img");
const dialog = document.createElement("dialog");
dialog.innerHTML = `
<img src="${el.href}" alt="${thumbImage.alt}" >
<form method="dialog">
<button value="close">Close</button>
</form>
<form method="dialog">
<button value="prev">Previous</button>
<button value="next">Next</button>
</form>
`;
dialog.addEventListener("close", this.handleCloseLightBox);
this.#lightBoxes.set(el, dialog);
this.append(dialog);
el.addEventListener("click", this.handleOpenLightBox);
}
doBreakdown() {
if (this.#lightBoxes.size) {
this.#lightBoxes.entries()?.forEach(([el, dialog]) => {
dialog.removeEventListener("close", this.handleCloseLightBox);
this.removeChild(dialog);
el.removeEventListener("click", this.handleOpenLightBox);
});
this.#lightBoxes.clear();
}
}
doStartup() {
this.doBreakdown();
this.querySelectorAll("*:not(dialog) a:has(img)").forEach(
this.createLightBox.bind(this)
);
}
connectedCallback() {
this.doStartup();
}
adoptedCallback() {
this.doStartup();
}
disconnectedCallback() {
this.doBreakdown();
}
}
customElements.define("light-box", LightBox);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.