PELAGIC ZONE

Filtered Art Gallery

This is my thought log from creating an art gallery (with filters, a lightbox, and a "backend" database file to pull metadata from) from scratch, essentially. This is not intended to be a tutorial, more a stream of thought as to why I made the design choices I did. Notably, the author is quite pedantic and loves including lots of customized detail, and there are likely much more elegant and less tedious ways to create something like this. As of 2026, you can see the gallery here.

Resource Roundup

Initial Thoughts

Who knew creating an art gallery would be such an adventure? I apparently did, because I put off coding this for a long time because I knew I'd be really particular about how it appears.

I thought, hey, wouldn't it be cool to have an art gallery that's filterable by "tags" a la Tumblr? But then I went down a rabbit hole of how to apply filters and quickly got overwhelmed. I sat down and made a list of components I'd ideally like in an art gallery:

  1. Lightbox feature, where you can open the image larger on a click.
  2. Caption support, so I can talk about my images.
  3. It needs to be navigable (or ideally, also look good) at multiple viewports.
  4. It should be filterable by topic, year, etc.

Backing up and organizing my art

To start off, I decided to actually back up my art blog and download all of my art (from 2013 to present) to see what I was actually working with. I used TumblThree for this purpose, and it worked great! You can customize the data it pulls, and even specify a file name format. I made date the first part of my file name and sorted everything chronologically, and eventually sorted my art by year into different folders.

Deciding on a format

After looking at what I had downloaded, I noticed my art is of many differing dimensions, ratios, and levels of polish. I had two options here, visually:

  1. A masonry gallery, like how Pinterest is laid out. This is nice for a mixture of images with both horizontal and vertical layouts.
  2. A grid gallery where every image has a thumbnail of the same size.

At the suggestion of my friend I mocked up the masonry gallery first, and decided I didn't like how it looked on my current website. It seemed cluttered! And most importantly, on mobile all the images just because one long string of pictures, which would not work for a gallery of this size. I think if I used this type of format, it'd be great for a highly curated portfolio page that has a different layout than the rest of my site entirely. I've always enjoyed this really simple template provided by Kaylee Rowena.

That means it was time to try a gallery with same-sized thumbnails. For this, I already had some structure to work off because other parts of my site have photo galleries with a similar layout. I made some edits to this and made sure it was responsive, and began to set up my gallery.

I have lightboxes on other parts of my site, but this time I wanted more flexibility. I wanted the ability to add a caption, and be able to use both HTML and CSS in tandem to customize that caption box. For a lot of use-out-of-the-box lightbox scripts, this is a bit of a tall order. However, by chance, I stumbled across A Little Light Lightbox, which is a super lightweight and flexible lightbox code. The challenge here is that the captions will render using the <span> tag, and any usage of quotation marks completely breaks the caption. This means no in-line links, style tags, or image embeds. With a little fiddling in the code, I was able to wrap the caption content in a <div> tag and use targeted selectors, such as only targeting the "i" (italics) selector for formatting, in a tricky way in order to format this how I liked without touching the actual text input in the HTML too much. This included some crazy applications of the <details> tag to add commentary that could be opened on a click.

Filtering

Now for the hardest part, as this is something I've never done. There were two options that I knew were available to me.

  1. CSS/HTML-only filtering, using radio buttons and :has selectors. This is a tutorial I had come across for applying filters this way.
  2. Javascript, which is the usual way to filter items on a webpage. I had come across this tutorial for the most basic script to filter items.

I'm usually trying to keep things as lightweight on the JS as possible. It's not always supported and can slow down your site, and I'm not as familiar with the language. However, after reflecting on how big this gallery could possibly become, CSS filtering every individual item was going to be a huge pain... time to learn something new!

I started by using the basic Javascript filtering tutorial I linked above, and at first it seemed to work! And was fairly lightweight! Yay! But the more images I added, the more quickly it became clear there was a problem. It did not fully remove each image when filtered out, so the grid was becoming misaligned the more images I added (and subsequently filtered). Woe.

After trawling around (there's so many ways to apply filters, apparently, and they're all written differently), I found this tutorial which seemed to keep everything aligned nicely, and made major modifications. I don't quite like that everything has to be within the container to be acted upon, but a small price to pay...

Now, things seemed to be in line. I could proceed with populating all of my images... except, this quickly became an untenable process as each picture required a HUGE chunk of HTML in order to include the lightbox, title, date, description, alt text, file paths... I am usually not one who minds the tedium of manually editing a lot of HTML, but this was quickly going to become annoying. Was there another way?

Using a JSON File for Image Metadata

In the past, I've made some complicated spreadsheets before with a "front end" that pulls data from a "back end" database through a Rube-Goldberg machine chain of commands, why not make something like this but for my images? I knew I wanted each image to be highly customized with its own information including description, alt text, date, title etc. which still has to be done manually. But there had to be a way to clean up the format and make that process slightly less tedious than copy-pasting large chunks of HTML tags over and over. Was there a way I could make a "database" file and pull from that in order to populate the page?

Enter the humble JSON file. Now, this is something I have never done before. I don't think I've touched JSON files since I was installing Minecraft mods over 10 years ago. But this seemed to be the solution in tandem with 11ty's support for global data files. This way, I could make one big file of all of my images, their associated metadata, and file paths. And theoretically, this could dynamically update as I add new images without me touching the HTML. This tutorial was really helpful for learning how to format the image metadata.

Here's an example of how that looks. I chose to group things off by year for organizational purposes.

.../_data/gallery.json

  "2026": [
  {
    "src": "/images/art/2026/file1.png",
    "title": "Image Title 1",
    "date": "DD/MM/YYYY",
    "tags": "example1",
    "description": "Optional image caption here.",
    "alt": "Text for screenreaders here."
  },

{
    "src": "/images/art/2026/file2.png",
    "title": "Image Title 2",
    "date": "DD/MM/YYYY",
    "tags": "example1 example2",
    "description": "Optional image caption here.",
    "alt": "Text for screenreaders here."
  },
]

Now, to use for loops to populate the gallery. I've used for loops before (mostly in R, for work purposes), but it had been a while. This, to my understanding, tells the computer "every time you encounter information within this one collection, generate this code block using that information, and repeat until you run out of information". In this case, we want to generate the same-format code block for the art pieces, but changing that metadata information each time.

This for loop is written in the Nunjucks templating language, as this is just what I use with 11ty. I modified the HTML structure to pull variables from the JSON file when prompted. This is going to look like a jumble to you, because I have my images formatted in a very particular way, but what I think is important to see is what is enclosed in curly brackets. When you see this, it pulls information from the JSON sheet for each art data entry. For example, {{ image.tags }} adds the filter tags for that image to the code, while {{ image.date }} displays the date where I specify. The additional description for my art is optional, so I've enclosed it in a {{% if image.description %}} tag. If there is no image description present in the file, the code generates without it.

{% for image in gallery["2026"] %}
<div class="gallery-item {{ image.tags }}">
<div class="gallery-item-inner"><a href="{{ image.src }}" data-lightbox
data-caption="<div><b>{{ image.title }}</b><br><i>{{ image.date }}</i>{% if image.description %}<br><details><summary>More Info »</summary>{{ image.description }}</details> {% endif %}</div>">
    <img src="{{ image.src }}" alt="{{ image.alt }}"></a>
	</div></div>{% else %}
      <span><i>To be added.</i></span>
    {% endfor %}

There's also a small component I added where if there is nothing in that JSON file to be pulled that meets the selected criteria, it displays the message "To be added" in plain text. This is helpful for previous year sections for art in my JSON file that I haven't gotten around to adding anything to yet; for example it would display if the "2024" section of my JSON file was currently blank because I had not added image data there yet.

This has many benefits, but if I ever decide to change the format of this gallery, all metadata should be preserved.

Notable drawbacks to the gallery at present is that I cannot use lightbox galleries (the ability to move between images using arrows while the lightbox is open), because it does not respect the filter feature. I've seen people overcome this before, but this requires more JS knowledge than I have at present to fix. It can also be a bit slow, though it still loads <5 seconds on my infamously slow apartment wifi. I use pinga to optimize images, which usually works quite well, but on a page with so much content, there is only so much it can do!

This took quite a bit of time to set up, and I'm sure if I understood JS a bit more it would be much more streamlined. But this seems to work well enough for now. Now to manually populate that JSON file with all the art metadata, which I think will become an ongoing project... but at least to populate a backlog, you only have to do it once. This is the first time in my life I've wished I've drawn less, so there'd be less to fill out!