An orange rock ridge against a blue sky and a low moon
Delicate Arch, Arches National Park, Moab, Utah

I’ve covered basic image galleries with CSS and PHP in previous articles, making it time to do the same thing with JavaScript.

Image Options

As with the other image gallery examples, we need a two versions of each image: a thumbnail image and a full-size image. In this case, you have two options for the images:

  1. Save the image versions with the same name, placing them in different folders: thumbnails and fullsize. This is probably the best option for sites with many resources, and is the route taken in the code for this article.
  2. Provide the images with different filenames, and store them in the same location: for example, newyork-full.jpg (the fullsize image) and newyork.jpg (the thumbnail). The CodePen demo for this article uses this approach.

The Markup

The markup is very similar to previous examples:

<div id="gallery">
    <div id="thumbs">
        <input type="image" src="thumbnails/desert.jpg" alt="A broad and empty desert">
        <input type="image" src="thumbnails/watchtower.jpg" alt="An empty watchtower on the edge of the Grand Canyon">
        <input type="image" src="thumbnails/namib.jpg" alt="Pools of salt in the Namib Desert">
        <img src="fullsize/desert.jpg" alt id="fullsize">
        <figcaption>A broad and empty desert</figcaption>

The image input elements make the gallery keyboard navigatable, and thus accessible, as well as providing a pointer hint on hover. Perhaps surprisingly, the element also supports srcset for Retina images. (Read on for an example of this).


The easiest way to arrange the gallery is with :

body { background: #111; color: #fff; }
div#gallery { display: flex; flex-direction: column; }
div#gallery div > input { width: 33%; }
div#gallery figure img { width: 100%; }

The result is what you see at the top of this article.

The Script

Added to the bottom of the page:

var caption = document.querySelector("#gallery figcaption"),
thumbs = document.getElementById("thumbs"),
fullsize = document.getElementById("fullsize");
thumbs.addEventListener("click", function(e) {
    var filename ="/").pop();
    fullsize.src = "fullsize/"+filename;
    caption.innerHTML =;

An explanation: after identifying the appropriate elements, the script uses event propagation to determine which thumbnail the user has clicked on. The filename for the fullsize image is determined by splitting the file path for the thumbnail into an array and popping off the last element, concatenating the result to fullsize/. The thumbnail image’s alt attribute is used to set the caption text for the fullsize version.

Adding Retina Support

Adding support for HiDPI images is fairly straightforward. The input elements change to:

<input type="image" src="thumbnails/delicate-arch-moab.jpg"
srcset="thumbnails/delicate-arch-moab-2x.jpg 2x" 
alt="Delicate Arch, Arches National Park, Moab, Utah">

And the script sets both the src and srcset attributes of the large image:

var filename ="/").pop();
var fileNameArr = filename.split(".");
fullsize.src = "fullsize/"+fileNameArr[0]+"."+fileNameArr[1];
fullsize.srcset = "fullsize/"+fileNameArr[0]+"-2x."+fileNameArr[1]+" 2x";

In this version, the filename is further split to separate out the extension; it is recombined to produce the filename for 2x images (e.g. fullsize/moab-2x.jpg)

Limitations & Drawbacks

While effective, there are a few limitations to this technique, at least as presented here:

  1. There is no progressive enhancement to this technique; if the user doesn’t run JavaScript, they won’t see any fullsize image except the default one. See the next article for a possible solution to this problem.
  2. There is no history of user actions on the page, although this could be added via the History API.
  3. Unlike the , there’s no way to direct users to a particular image via a link; again, this could be altered by manipulating and reading the browser URL.

Photographs by Mariusz Kluzniak and James Marvin Phelps, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at to learn more.
Check out the CodePen demo for this article at