Image Gallery Shortcode

Learn how to use the image gallery shortcode to create responsive galleries with thumbnails, captions, and a JavaScript-powered lightbox.

BLZR

DemoImageShortcode

2172  Words … ⏲ Reading Time:9 Minutes, 52 Seconds

2026-05-11 04:30 +0000


The gallery shortcode lets you add a beautiful, responsive image gallery to any page on your Hugo site. You compose it using nested {{< figure >}} shortcodes — one per image — giving you full control over captions, titles, and links without any extra tooling or third-party libraries.

What You Get

  • Two layout modes — a uniform square grid, or a masonry layout where images keep their natural height
  • Automatic thumbnails — for images stored in your /assets folder, a square smart-cropped thumbnail is generated at build time; the full-resolution image is loaded only when the lightbox opens
  • Lightbox — clicking any thumbnail opens the full image in a modal overlay with title, caption, previous/next navigation, and keyboard controls
  • Native SVG Support.svg files are automatically detected and rendered without box shadows so transparent graphics blend perfectly into the page
  • Granular Alignment — control the vertical alignment of specific images in your masonry layouts using utility classes
  • No-JS warning — if JavaScript is disabled, hovering over a thumbnail shows a clear message instead of silently doing nothing
  • SEO & accessibility built in — structured data, meaningful alt text, lazy loading, ARIA roles, and URL-hash navigation so every open image has its own linkable URL
  • No external libraries — pure vanilla JavaScript and SCSS

Before the shortcode will render, add this to your hugo.toml:

[params.gallery]
  enable    = true
  thumbnail = "300"   # thumbnail size in pixels — default is 300
  layout    = "grid"  # default layout: "grid" or "masonry"
  • enablerequired. The gallery will not render without this.
  • thumbnail — controls the width and height of generated thumbnails in pixels.
  • layout — sets the default layout for all galleries on your site. You can override this per gallery with the mode parameter (see below).

Wrap one or more {{< figure >}} shortcodes inside {{< gallery >}}:

{{< gallery >}}
  {{< figure src="images/photo1.jpg" title="Sunset" caption="Taken at the coast" >}}
  {{< figure src="images/photo2.jpg" title="Mountains" caption="Early morning hike" >}}
  {{< figure src="images/photo3.jpg" caption="City lights" >}}
{{< /gallery >}}

That is all the minimum setup requires. Hugo will generate thumbnails, wire up the lightbox, and output SEO-friendly markup automatically.

Layout Modes

Grid

The default layout. Every image is displayed as a uniform square cell. Images are cropped to fill the square (smart crop — the most interesting part of the image is preserved). Cells are centred when there are fewer images than would fill a full row.

{{< gallery mode="grid" >}}
  {{< figure src="images/a.jpg" title="A" caption="First image" >}}
  {{< figure src="images/b.jpg" title="B" caption="Second image" >}}
  {{< figure src="images/c.jpg" title="C" caption="Third image" >}}
{{< /gallery >}}

Masonry

Images keep their natural height, creating a staggered, Pinterest-style layout. Useful when your images have varying aspect ratios and you want to show them without cropping. Sparse rows (fewer images than fill the full width) are centred.

{{< gallery mode="masonry" >}}
  {{< figure src="images/landscape.jpg" caption="Wide shot" >}}
  {{< figure src="images/portrait.jpg" caption="Tall shot" >}}
{{< /gallery >}}

Tip: The mode parameter always overrides the layout value you set in hugo.toml. Set layout to whichever mode you use most often, then use mode on the shortcodes where you need something different.

The figure Parameters

Each {{< figure >}} inside a gallery accepts the following parameters:

ParameterRequiredDescription
srcYesPath to the image. See Image Sources below.
titleNoShown as a bold heading in the lightbox above the caption.
captionNoDescriptive text shown in the lightbox and on thumbnail hover. Supports Markdown.
altNoAlt text for the image. Defaults to title, then caption, then the filename. Always set this when your image conveys meaning not covered by the caption.
attrNoAttribution or credit line, shown alongside the caption.
attrlinkNoURL to link the attribution text to.
linkNoIn standalone {{< figure >}} use (outside a gallery), wraps the image in a link. Inside a gallery, this is used as the lightbox full-resolution URL for static and remote images.
loadingNoOverride the loading behaviour. Defaults to lazy inside a gallery. Set to eager for the first image if it is above the fold.
classNoCSS class applied to the <figure> element. Inside a masonry gallery, you can use align-top, align-center, or align-bottom to override vertical alignment for that specific image.

Image Sources

The shortcode handles three types of image paths:

Images stored in your /assets directory. Use the path relative to assets/:

{{< figure src="images/photo.jpg" >}}

This means the file lives at your-project/assets/images/photo.jpg.

Hugo’s image pipeline processes these at build time:

  • A square thumbnail is generated and used in the gallery grid
  • A WebP version is created (with JPEG fallback via <picture>)
  • The original full-resolution image is loaded only when the lightbox opens

2. Static files

Images stored in your /static directory. Prefix the path with /:

{{< figure src="/photos/event.jpg" >}}

This means the file lives at your-project/static/photos/event.jpg.

Static files are served as-is. Hugo cannot resize or convert them, so the same file is used for both the thumbnail display and the lightbox.

3. Remote images

Full http:// or https:// URLs to images hosted elsewhere:

{{< figure src="https://example.com/photo.jpg" caption="Photo from the web" >}}

Remote images cannot be resized by Hugo. The same URL is used for both thumbnail and lightbox. CSS handles the visual fit.

Clicking any thumbnail opens the lightbox. If you provided a title and/or caption, they appear below the enlarged image — title in bold, caption underneath.

ControlAction
Click thumbnailOpen lightbox at that image
/ arrow keysNavigate to previous / next image
EscapeClose the lightbox
Click outside the imageClose the lightbox
Browser back buttonClose the lightbox

Deep-linking to a specific image

When you open the lightbox, the URL automatically updates to include a hash like #gallery-abc123-2 (gallery ID + image index). This means:

  • You can copy and share a URL that opens directly to a specific image
  • The browser back button works as expected — pressing back closes the lightbox rather than leaving the page

No-JavaScript Warning

If a visitor has JavaScript disabled, the lightbox cannot open. Rather than leave them confused by an unresponsive click, the gallery shows a clear overlay message on hover:

⚠ Lightbox requires JavaScript

This overlay is shown by default using pure CSS and is automatically hidden as soon as gallery.js loads successfully. No configuration needed.

SEO and Accessibility

The gallery is built with search engines and assistive technology in mind. Here is what is applied automatically:

FeatureWhat it does
schema.org/ImageGalleryMarks the gallery container as a structured data entity for Google Image Search
schema.org/ImageObjectMarks each figure with its URL, name, and description for rich results
contentUrl metaGives crawlers the full-resolution image URL, even though the thumbnail is what’s displayed
Meaningful alt textFalls back through alttitlecaption → filename — no image is ever left without a description
loading="lazy"Gallery images load only as they scroll into view, improving page speed
decoding="async"Images decode off the main thread, keeping the page responsive
role="region" + aria-labelScreen readers announce the gallery as a named landmark
role="dialog" + aria-modal on lightboxScreen readers correctly identify the lightbox as a modal dialog
aria-live on captionScreen readers announce the caption when you navigate between images
role="button" + tabindex on controlsClose and navigation buttons are reachable by keyboard Tab

Configuration Reference

hugo.toml

[params.gallery]
  enable    = true      # Required — gallery will not render without this
  thumbnail = "300"     # Thumbnail dimension in px (width and height). Default: "300"
  layout    = "grid"    # Site-wide default layout: "grid" or "masonry". Default: "grid"

SCSS Variables

All colours and shadows are controlled by SCSS variables. Copy these into your theme’s assets/scss/_colors.scss (or equivalent) and edit to match your design:

// Gallery thumbnail cells
$gallery-item-box-shadow:       0 2px 4px rgba(0, 0, 0, 0.1)  !default;
$gallery-item-hover-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !default;
$gallery-item-caption-background: rgba(0, 0, 0, 0.7)          !default; // hover caption overlay
$gallery-item-caption-color:    #fff                           !default;
 
// Lightbox
$lightbox-overlay-background:           rgba(0, 0, 0, 0.85)   !default; // backdrop
$lightbox-image-box-shadow:             0 5px 15px rgba(0, 0, 0, 0.3) !default;
$lightbox-caption-color:                #fff                   !default;
$lightbox-close-nav-color:              #fff                   !default; // close & arrow buttons
$lightbox-close-color-hover:            #ccc                   !default;
$lightbox-nav-background-color:         rgba(0, 0, 0, 0.3)    !default;
$lightbox-nav-background-color-hover:   rgba(0, 0, 0, 0.6)    !default;

Full Examples

{{< gallery mode="grid" >}}
  {{< figure src="images/mountain.jpg"  title="Mountain" caption="Taken at sunrise · John" >}}
  {{< figure src="images/ocean.jpg"     title="Ocean"    caption="Pacific coastline" >}}
  {{< figure src="images/forest.jpg"    title="Forest"   caption="Autumn colours" >}}
{{< /gallery >}}

2 images

3 images

4 images

5 images

{{< gallery mode="masonry" >}}
  {{< figure src="images/mountain.jpg"  title="Mountain" caption="Taken at sunrise · John" >}}
  {{< figure src="images/ocean.jpg"     title="Ocean"    caption="Pacific coastline" >}}
  {{< figure src="images/forest.jpg"    title="Forest"   caption="Autumn colours" >}}
{{< /gallery >}}

2 images

3 images

4 images

5 images

Use attr and attrlink to credit the photographer or source:

{{< gallery mode="grid" >}}
  {{< figure src="images/city.jpg"
      title="City at Night"
      caption="Downtown skyline"
      attr="Jane Smith"
      attrlink="https://example.com/jane" >}}
  {{< figure src="images/market.jpg"
      title="Street Market"
      caption="Saturday morning"
      attr="Bob Jones" >}}
{{< /gallery >}}
{{< gallery mode="grid" >}}
  {{< figure src="/images/397-600x400.jpg"      title="IMAGE1"  caption="Image 1 from /static folder" >}}
  {{< figure src="/android-chrome-192x192.png"  title="IMAGE2"  caption="Image 2 from /static folder" >}}
  {{< figure src="/android-chrome-384x384.png"  title="IMAGE3"  caption="Image 3 from /static folder" >}}
{{< /gallery >}}
{{< gallery mode="masonry" >}}
    {{< figure src="https://picsum.photos/seed/gallery-remote1/800/600"  caption="Random 1" >}}
    {{< figure src="https://images.pexels.com/photos/3408744/pexels-photo-3408744.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"  caption="Random 2" >}}
    {{< figure src="https://picsum.photos/seed/c/800/800"  caption="Random 3" >}}
    {{< figure src="https://picsum.photos/seed/another-image/700/500?blur=2"  caption="Random 4" >}}
    {{< figure src="https://picsum.photos/seed/gallery-remote3/1024/768"  caption="Random 5" >}}
    {{< figure src="https://placehold.co/600x400?text=More+Examples"  caption="Random 6" >}}
{{< /gallery >}}

You can override the global masonry alignment for specific images using the class parameter (align-top, align-center, or align-bottom). Additionally, any .svg image will automatically have its box-shadow removed for a clean, integrated look.

{{< gallery mode="masonry" >}}
  {{< figure src="images/tall-photo.jpg" class="align-top" title="Photo" caption="Default alignment (top)" >}}
  {{< figure src="images/transparent-graphic.svg" class="align-center" title="SVG" caption="Centered and shadow-free" >}}
  {{< figure src="images/wide-photo.jpg" class="align-bottom" title="Photo" caption="Aligned to bottom" >}}
{{< /gallery >}}

If your hugo.toml sets layout = "grid" but one particular gallery should be masonry, just set mode on that shortcode:

# hugo.toml — site-wide default
[params.gallery]
  enable = true
  thumbnail = "300"
{{< gallery >}}                       <!-- uses grid (from hugo.toml) -->
  {{< figure src="images/a.jpg" >}}
{{< /gallery >}}

{{< gallery mode="masonry" >}}        <!-- overrides to masonry just for this gallery -->
  {{< figure src="images/b.jpg" >}}
{{< /gallery >}}

Important Notes

  • Path conventions matter. A path without a leading / (e.g. images/photo.jpg) is looked up in /assets. A path with a leading / (e.g. /images/photo.jpg) is looked up in /static. Getting this wrong will cause a build warning and the image will be skipped.
  • Write good captions. Alt text falls back to the caption if no explicit alt is set, so a descriptive caption improves both accessibility and SEO.
  • loading="lazy" is the default inside a gallery. If your first gallery image is visible immediately on page load (above the fold), add loading="eager" to that one figure so it does not delay rendering.
  • JavaScript is required for the lightbox. Thumbnails and captions are fully visible without JS; only the lightbox and navigation require it. Visitors without JS see a hover warning on each thumbnail.
  • Gallery JS is only loaded on pages that use the shortcode. It will not affect pages that have no gallery.