Add Image Lightbox to Hugo Theme
If you need to add an image lightbox to your Hugo theme and have no idea how to approach it, read this article, where I present a simple and effective technique for achieving this. It is a continuation of the series “Hugo Theme Recipes”.
Getting Started
What is an image lightbox? An image lightbox, also sometimes called an image modal zoom, is a window overlay that goes over the website’s currently displayed webpage to show a larger version of the image when the reader clicks on it. This “magnification” lets the reader view high-resolution images in great detail. Such a feature would be a great addition to a Hugo theme and, consequently, to a website based on such a Hugo theme.
So, where to start? It all comes down to two options. If you’re well versed in CSS and JavaScript, you can roll up your sleeves and implement an image lightbox yourself. The second option would be integrating an existing third-party image lightbox plugin into your Hugo theme. In my case, while working on the Bilberry Hugo theme, I opted for a third-party plugin since I’m not that good at CSS and JavaScript and didn’t have enough spare time to implement it myself, so the recipe shown below is based on a third-party plugin.
Pick & Test Plugin
First, picking a suitable plugin from the plethora of available ones might be challenging and time-consuming. Based on my experience, you can use the following selection criteria:
- It should be a relatively recent development with a public repository on GitHub, Bitbucket, etc.
- Its license should not be more restrictive than your Hugo theme license.
- It may also contain other functionalities, such as an image gallery, that you want to add to your Hugo theme.
Second, after narrowing down your choices, you must test selected plugins to see if they work well within your Hugo theme. It is possible that a plugin’s CSS may conflict with your theme’s CSS, and that may cause problems with your chosen plugin functioning correctly.
The technicalities of such testing will depend on the selected plugin and Hugo theme. Most lightbox plugin distributions
come in the form of CSS and JavaScript assets that you should manually add to your theme’s static
folder. For example,
the static
folder in the Bilberry Hugo theme will look like below after downloading and copying minified assets for
the DimBox plugin:
In your Hugo theme, you locate a partial template file containing the <head>
and <body>
tags. For instance, in the
Bilberry Hugo theme, such a partial template is
the layouts/_default/baseof.html
file. Next, include the plugin’s CSS and JavaScript assets in the <head>
and <body>
tags, respectively:
<head>
...
<link rel="stylesheet" href="dimbox.min.css" />
...
</head>
...
<body>
...
<script src="dimbox.min.js"></script>
...
</body>
After all this, it’s time to create a test article that contains an image. Place the raw HTML needed to
add an image within the article’s markdown according to the plugin documentation. For most plugins, it is a variation of
the <a>
tag with custom attributes, e.g., for the Dimbox plugin, that would be the following, given you copied
the my-test-image.jpg
image to the static
folder of your website:
<a href="my-test-image.jpg" data-dimbox="my-test-image">
<img src="my-test-image.jpg" alt="This is an awesome image" />
</a>
But since raw HTML is used to display the test image, Goldmark’s unsafe
property in the config.toml
file of your
website should be set to true
to render the above HTML block:
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true
Having confirmed with tests that the selected plugin works as expected, it’s time to start integrating it into the theme.
Integration with Theme
Integrating a plugin with a theme consists of two parts: the plugin’s assets integration and custom image render hook
implementation. The first part depends on how asset management and processing are implemented in your Hugo theme.
Suppose the theme does not use any tools for dependency management (e.g., npm) along with an asset processing pipeline (
e.g., Hugo pipes). In that case, it will suffice to save the plugin’s resource files in the static
folder of the theme
and include them in the theme’s corresponding partial template within the <head>
and <body>
tags, as we did earlier
while testing plugins.
If your theme does use dependency management and/or asset processing tools, the plugin’s assets will likely need to be
stored in the theme’s assets
folder, and certain changes will need to be made to the dependency management and asset
processing pipelines.
As for the second part, the default image render hook provided by Hugo,
namely layouts/_default/_markup/render-image.html
, needs to be replaced by a custom one that will take into account
the implementation details of the selected lightbox plugin. That’s because the default hook will render the markdown for
adding an image as the <img>
tag wrapped in the <p>
tag. More on render hooks can be read
in Hugo documentation.
![My Test Image](my-test-image.jpg)
For example, the above markdown will be rendered as follows:
<p>
<img src="full/path/to/my-test-image.jpg" alt="My Test Image">
</p>
As an illustration, a custom image render hook template for the DimBox plugin can be implemented as below:
<a href="{{ .Destination | safeURL }}" data-dimbox data-dimbox-caption="{{ .Text }}">
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
</a>
The above implementation will produce the following HTML for the image markdown:
<a href="full/path/to/my-test-image.jpg" data-dimbox="" data-dimbox-caption="My Test Image">
<img src="full/path/to/my-test-image.jpg" alt="My Test Image">
</a>
You can also enhance your image render hook for displaying figures, that is, images with a caption or legend at the
bottom. The markdown for adding an image may contain an optional part, named Title
, immediately after the path to the
image:
![My Test Image](my-test-image.jpg "Fig. 1 - My Test Image Caption")
You can add a condition to check if the image markdown contains the Title
part. If so, the <a>
tag along with
the <figcation>
tag should be wrapped into the <figure>
tag:
{{ if .Title }}
<figure>
<a href="{{ .Destination | safeURL }}" data-dimbox data-dimbox-caption="{{ .Text }}">
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
</a>
<figcaption>{{ .Title }}</figcaption>
</figure>
{{ else }}
<a href="{{ .Destination | safeURL }}" data-dimbox data-dimbox-caption="{{ .Text }}">
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" />
</a>
{{ end }}
That will generate the following HTML for the image markdown containing Title
:
<figure>
<a href="full/path/to/my-test-image.jpg" data-dimbox="" data-dimbox-caption="My Test Image">
<img src="full/path/to/my-test-image.jpg" alt="My Test Image">
</a>
<figcaption>Fig. 1 - My Test Image Caption</figcaption>
</figure>
The recipe presented above is based on my hands-on experience working on the new major release of the Bilberry Hugo theme. This theme already supported the modal image zoom via the Magnific Popup plugin. After migrating CSS and JavaScript assets processing from npm and Laravel Mix to Hugo Pipes, this plugin stopped working, and I could not pinpoint the root cause of that. Therefore, I had no choice but to replace the Magnific Popup plugin with a new one, DimBox. For more information, see this commit.
Continue reading the series “Hugo Theme Recipes”: