I wanted a simple way to display a thumbnail image that visitors could click to see the full-size image.
Nothing complicated. No gallery extension. No lightbox library. And, most importantly, no JavaScript.
It turns out that modern HTML can do most of the work for us using the popover attribute.
Jump to the end to see an example
The basic idea
The HTML Popover API allows one element to control another element. A button gets a popovertarget attribute and the element that we want to display gets a popover attribute.
For example:
<button popovertarget="my-popover" type="button">
Open popover
</button>
<div id="my-popover" popover>
Hello!
</div>
That's it. There is no JavaScript involved.
The value of popovertarget is the ID of the element that should be displayed. In this example, popovertarget="my-popover" targets the element with id="my-popover".
Turn the thumbnail into a button
Instead of a text button, we can put our thumbnail image inside the button:
<button popovertarget="photo-1" type="button" class="image-thumbnail">
<img src="/thumb.jpg" alt="Joomla World Conference">
</button>
I'm deliberately using a <button> rather than an <a> element.
This isn't a link to another resource. It is an action: clicking it opens the larger image. A button is therefore the more appropriate HTML element.
The alt attribute provides the alternative text for the image. This is important because the visual magnifying-glass indicator we are about to add is purely decorative.
Create the popover
Now we need the element that will contain the full-size image:
<div id="photo-1" popover>
<img src="/photo.jpg" alt="Joomla World Conference">
</div>
Notice that the ID, photo-1, matches the value of popovertarget on the button.
When the button is activated, the browser displays the popover. When the popover is dismissed, the browser hides it again.
No JavaScript is required.
Adding a close button
An automatic popover can be dismissed by pressing Escape or by clicking outside it. However, I also want to provide an obvious Close button.
<div id="photo-1" popover>
<button
popovertarget="photo-1"
popovertargetaction="hide"
type="button"
aria-label="Close">
×
</button>
<img src="/photo.jpg" alt="Joomla World Conference">
</div>
The popovertargetaction="hide" attribute tells the browser that this button should hide the popover.
The aria-label gives the button a meaningful accessible name. The × is simply the visual representation of the close button.
Making it look like a lightbox
By default, a popover isn't going to look much like a lightbox. A little CSS can change that.
.image-popup {
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
margin: 0;
padding: 2rem;
border: 0;
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 85%);
}
.image-popup:popover-open {
display: flex;
}
.image-popup::backdrop {
background: rgb(0 0 0 / 85%);
}
.image-popup img {
max-width: 95vw;
max-height: 95vh;
width: auto;
height: auto;
}
.image-popup-close {
position: absolute;
top: 1rem;
right: 1rem;
}
There is one important detail here.
We don't put display: flex directly on .image-popup. The browser normally hides a popover when it is closed. Setting display: flex directly on the element overrides that behaviour and makes the popover visible all the time.
Instead, :popover-open targets the popover only while it is actually open. This allows us to use flexbox for positioning the image without overriding the browser's built-in popover behaviour.
The ::backdrop pseudo-element lets us style the area behind the popover.
Adding a magnifying glass
There is one small usability problem left.
A sighted visitor looking at a thumbnail doesn't necessarily know that clicking the image will display a larger version.
We can add a small magnifying glass in the bottom-right corner of the thumbnail using CSS.
Rather than drawing the magnifying glass from separate CSS shapes, I'm using a small SVG embedded directly into the CSS as a data:image. This means there is no separate SVG file to load, and the entire effect remains contained within the stylesheet.
First, make the thumbnail button a positioning context:
.image-thumbnail {
position: relative;
display: inline-block;
padding: 0;
border: 0;
background: none;
cursor: pointer;
}
.image-thumbnail img {
display: block;
}
Then add the magnifying glass as a pseudo-element:
/* Magnifying glass */
.image-thumbnail::after {
content: "";
position: absolute;
right: 0.75rem;
bottom: 0.75rem;
width: 1.25rem;
height: 1.25rem;
background-color: rgb(0 0 0 / 60%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='16.65' y1='16.65' x2='21' y2='21'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 65%;
border-radius: 50%;
pointer-events: none;
}
The dark circular background provides contrast against the thumbnail, while the SVG provides the actual magnifying-glass symbol. The background-size: 65% keeps the magnifying glass itself smaller than the circular background.
I prefer leaving it permanently visible rather than only showing it when the mouse is hovering over the image. That way the visual indication is also available to people using touchscreens, where there is no hover state.
Don't forget keyboard focus
Because the thumbnail is a real button, it can be reached using the keyboard. We should therefore make its focus state visible:
.image-thumbnail:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
The magnifying glass is purely decorative, so it doesn't need to be announced by a screen reader. The button itself provides the interaction, and the image provides its alternative text.
The complete example
Putting everything together, this is the complete HTML:
<button
popovertarget="photo-1"
type="button"
class="image-thumbnail">
<img
src="/thumb.jpg"
alt="Joomla World Conference">
</button>
<div
id="photo-1"
popover=""
class="image-popup">
<button
popovertarget="photo-1"
popovertargetaction="hide"
type="button"
class="image-popup-close"
aria-label="Close">
×
</button>
<img
src="/photo.jpg"
alt="Joomla World Conference">
</div>
And the complete CSS:
.image-thumbnail {
position: relative;
display: inline-block;
padding: 0;
border: 0;
background: none;
cursor: pointer;
}
.image-thumbnail img {
display: block;
}
/* Magnifying glass */
.image-thumbnail::after {
content: "";
position: absolute;
right: 0.75rem;
bottom: 0.75rem;
width: 1.25rem;
height: 1.25rem;
background-color: rgb(0 0 0 / 60%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='16.65' y1='16.65' x2='21' y2='21'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 65%;
border-radius: 50%;
pointer-events: none;
}
/* Keyboard focus */
.image-thumbnail:focus-visible {
outline: 3px solid currentColor;
outline-offset: 3px;
}
/* The image popup */
.image-popup {
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
margin: 0;
padding: 2rem;
border: 0;
align-items: center;
justify-content: center;
background: rgb(0 0 0 / 85%);
}
/* Only display the popover as flex when it is open */
.image-popup:popover-open {
display: flex;
}
/* Background behind the popover */
.image-popup::backdrop {
background: rgb(0 0 0 / 85%);
}
/* Full-size image */
.image-popup img {
max-width: 95vw;
max-height: 95vh;
width: auto;
height: auto;
}
/* Close button */
.image-popup-close {
position: absolute;
top: 1rem;
right: 1rem;
}
One small thing about popover=""
If you're putting this into Joomla using TinyMCE, you may notice that the editor changes:
<div popover>
to:
<div popover="">
Don't panic. They mean the same thing. popover is a Boolean-style HTML attribute. Its presence is what matters, so an empty value is perfectly valid.
Note:
I always recommend that you set tinyMCE to use Joomla filters and not its own so that's what I have tested this with.
Why not just use JavaScript?
Of course, JavaScript could do this. There are plenty of libraries that can create sophisticated lightboxes with galleries, animations, zooming, captions and all sorts of other features.
But if all I want to do is show a larger image when somebody clicks a thumbnail, adding a JavaScript dependency seems rather excessive.
The browser already knows how to open and close a popover.
The HTML already knows what a button is.
CSS already knows how to position and style things.
So why add JavaScript?
The result
We now have a clickable thumbnail with a visual magnifying-glass indicator, a full-size image displayed over the page, a close button and keyboard support.
And the whole thing is built with HTML and CSS.
Zero JavaScript.
That's quite a nice improvement over the days when displaying an image in a box over a web page required a JavaScript library, three event handlers and a prayer.
Demo




Congratulations, you discovered a hidden secret!