Reusable image carousels in Hugo
I wanted to be able to display multiple different image carousels within a single Hugo blog. Here’s a little hack I made to an existing Hugo image carousel implementation that let me achieve that.
In searching around for a good image carousel implementations suitable for Hugo blogs, my searches frequently pointed back to this site right here. And it is indeed a good one, so kudos to the author! However, it had one main flaw that made it unsuitable for my purposes - I wanted multiple carousels, each with their own set of distinct images.
The site’s implementation had a hard dependency on a carousel yaml file named carousel.yaml
, which is where all the carousel images are defined. I wanted to be able to have a Hugo shortcode that let me define the name of the carousel as a parameter, and then look up a yaml file named accordingly.
So if you’ve arrived here via searching for a similar thing, read on! Here’s what I did. I will note, though - I’m by no means going to claim that I’m proficient at Hugo and landed on this solution with the partial help of LLMs, so, if you’re aware of a better way.. please do mention so in the comments!
My main change was to modify the layouts/shortcodes/carousel.html
file to be this, instead:
{{ .Scratch.Set "height" (.Get "height") }}
{{ .Scratch.Set "unit" (.Get "unit") }}
{{ .Scratch.Set "ordinal" .Ordinal }}
{{ .Scratch.Set "items" (.Get "items") }}
{{ $carouselName := (.Get "name") }}
{{ $carouselData := index .Site.Data (print $carouselName) }}
<div id="carousel{{ .Ordinal }}" class="carousel" duration="{{ .Get `duration` }}">
<ul>
{{ range $index, $slide := $carouselData.images }}
<li id="c{{ $.Scratch.Get "ordinal" }}_slide{{ add $index 1}}" style="min-width: calc(100%/{{ $.Scratch.Get "items" }}); padding-bottom: {{ $.Scratch.Get "height" }}{{ $.Scratch.Get "unit" }};">
<img src="{{ $slide.image }}" alt="" />
<div><div>{{ $slide.content_html }}</div></div>
</li>
{{ end }}
</ul>
<ol>
{{ range $index, $page := $carouselData.images }}
<li><a href="#c{{ $.Scratch.Get "ordinal" }}_slide{{ add $index 1 }}"></a></li>
{{ end }}
</ol>
<div class="prev">‹</div>
<div class="next">›</div>
</div>
Notably, this part now uses a name
parameter to load the data from a corresponding <name>.yml
file into carouselData
:
{{ $carouselName := (.Get "name") }}
{{ $carouselData := index .Site.Data (print $carouselName) }}
and then we iterate over carouselData
in the main block:
{{ range $index, $page := $carouselData.images }}
<li><a href="#c{{ $.Scratch.Get "ordinal" }}_slide{{ add $index 1 }}"></a></li>
{{ end }}
Then, in the blog, I can use the shortcode like this:
<carousel name="my-carousel" ... >
and, based on the name
parameter, Hugo will look for a data/my-carousel.yml
file to define the images used in that carousel.
It’s a small change, but it allowed me to feature multiple carousels on blogs such as my previous one.
Hope this helps! And, of course, full credit to the original carousel author for their excellent work to pivot off.