Image gallery do not show images

Hi,
I am new to hugo and toml markdown and i try to display an image gallery, but I do not get any images or errors. The site(main part) is blank.

Here is my toml file:

+++
title = "Logos"

[logos]
    [logos.inexoarablez]
    headline = "Inexorablez"
    [logos.inexoarablez.alt-tag]
        title1 = "Inexorablez #1"
        title2 = "Inexorablez #2"
        title3 = "Inexorablez #3"

    [logos.inexoarablez.thumbs]
        image1 = "/images/logos/inexorablez/inexorablez-01-thumb.webp"
        image2 = "/images/logos/inexorablez/inexorablez-02-thumb.webp"
        image3 = "/images/logos/inexorablez/inexorablez-03-thumb.webp"

    [logos.inexoarablez.images]
        img1 = "/images/logos/inexorablez/inexorablez-01.webp"
        img2 = "/images/logos/inexorablez/inexorablez-01.webp"
        img3 = "/images/logos/inexorablez/inexorablez-01.webp"

    [logos.kettenbeil]
    headline = "Kettenbeil"
    [logos.kettenbeil.alt-tag]
        title1 = "Kettenbeil #1"
        title2 = "Kettenbeil #2"
        title3 = "Kettenbeil #3"
    [logos.kettenbeil.thumbs]
        image1 = "/images/logos/kettenbeil/kettenbeil-01-thumb.webp"
        image2 = "/images/logos/kettenbeil/kettenbeil-02-thumb.webp"
        image3 = "/images/logos/kettenbeil/kettenbeil-03-thumb.webp"
    [logos.kettenbeil.images]
        img1 = "/images/logos/kettenbeil/kettenbeil-01.webp"
        img2 = "/images/logos/kettenbeil/kettenbeil-01.webp"
        img3 = "/images/logos/kettenbeil/kettenbeil-01.webp"

    [logos.superior-attack]
    headline = "Superior-Attack"
    [logos.superior-attack.alt-tag]
        title1 = "Superior-Attack #1"
        title2 = "Superior-Attack #2"
        title3 = "Superior-Attack #3"

    [logos.superior-attack.thumbs]
        image1 = "/images/logos/superior-attack/superior-attack-01.png"
        image2 = "/images/logos/superior-attack/superior-attack-02.png"

    [logos.superior-attack.images]
        img1 = "/images/logos/superior-attack/superior-attack-01.png"
        img2 = "/images/logos/superior-attack/superior-attack-01.png"
+++

my HTML code:

{{ with .Params.logos }}
{{ with .thumbs }}
  {{ range . }}
    <div class="row">
        <div class="column">
            <img src="{{ .image1 }}" style="width:100%" onclick="openModal();currentSlide(1)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image2 }}" style="width:100%" onclick="openModal();currentSlide(2)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image3 }}" style="width:100%" onclick="openModal();currentSlide(3)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image4 }}" style="width:100%" onclick="openModal();currentSlide(4)" class="hover-shadow cursor">
        </div>
    </div>
  {{ end }}
{{ end  }}

{{ with .images }}
{{ range . }}
<div id="myModal" class="modal">
  <span class="close cursor" onclick="closeModal()">&times;</span>
  <div class="modal-content">

    <div class="mySlides">
      <div class="numbertext">1 / 4</div>
      <img src="{{ .img1 }}" style="width:100%">
    </div>

    <div class="mySlides">
      <div class="numbertext">2 / 4</div>
      <img src="{{ .img2 }}" style="width:100%">
    </div>

    <div class="mySlides">
      <div class="numbertext">3 / 4</div>
      <img src="{{ .img3 }}" style="width:100%">
    </div>
    
    <div class="mySlides">
      <div class="numbertext">4 / 4</div>
      <img src="{{ .img4 }}" style="width:100%">
    </div>
    
    <a class="prev" onclick="plusSlides(-1)">&#10094;</a>
    <a class="next" onclick="plusSlides(1)">&#10095;</a>

    <div class="caption-container">
      <p id="caption"></p>
    </div>

    <div class="column">
      <img class="demo cursor" src="{{ .img1 }}" style="width:100%" onclick="currentSlide(1)" alt="Nature and sunrise">
    </div>
    <div class="column">
      <img class="demo cursor" src="{{ .img2 }}" style="width:100%" onclick="currentSlide(2)" alt="Snow">
    </div>
    <div class="column">
      <img class="demo cursor" src="{{ .img3 }}" style="width:100%" onclick="currentSlide(3)" alt="Mountains and fjords">
    </div>
    <div class="column">
      <img class="demo cursor" src="{{ .img4 }}" style="width:100%" onclick="currentSlide(4)" alt="Northern Lights">
    </div>
  </div>
</div>

and the script:

<script>
  // Open the Modal
  function openModal() {
    document.getElementById("myModal").style.display = "block";
  }
  
  // Close the Modal
  function closeModal() {
    document.getElementById("myModal").style.display = "none";
  }
  
  var slideIndex = 1;
  showSlides(slideIndex);
  
  // Next/previous controls
  function plusSlides(n) {
    showSlides(slideIndex += n);
  }
  
  // Thumbnail image controls
  function currentSlide(n) {
    showSlides(slideIndex = n);
  }
  
  function showSlides(n) {
    var i;
    var slides = document.getElementsByClassName("mySlides");
    var dots = document.getElementsByClassName("demo");
    var captionText = document.getElementById("caption");
    if (n > slides.length) {slideIndex = 1}
    if (n < 1) {slideIndex = slides.length}
    for (i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
    }
    for (i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace(" active", "");
    }
    slides[slideIndex-1].style.display = "block";
    dots[slideIndex-1].className += " active";
    captionText.innerHTML = dots[slideIndex-1].alt;
  }
  </script>

My main part is empty.. maby have a look on my repo. (single.html and gallery-logos.html)
my github repo

Thanks :slight_smile:

There may be other problems with your code, but…

  • .Params.logos.thumbs doesn’t exist
  • .Params.logos.images doesn’t exist

hm.. maby my toml file has got some errors

Which thumbs and images do you want? You have them under inexoarablez, kettenbeil, and superior-attack, but you do not include any of these keys in your rendering code.

https://gohugo.io/templates/introduction/#context

I want all of them.. three times on one site.
For example one gallery for inexorables one for kettenbeil and one for superior-attack. But all of them on one site.

So if I click on kettenbeil all logos for kettenbeil in one gallery. :face_savoring_food:

See my previous comment.

If I do this it is working.. but I want all (inexorablez + kettenbeil + superior-attack)

[logos]
    [logos.inexorablez]
    headline = "Inexorablez"
    [[logos.inexorablez.thumbs]]
        image1 = "/images/logos/inexorablez/inexorablez-01-thumb.webp"
        image2 = "/images/logos/inexorablez/inexorablez-02-thumb.webp"
        image3 = "/images/logos/inexorablez/inexorablez-03-thumb.webp"
{{ range .Params.logos.inexorablez.thumbs }}
    <div class="row">
        <div class="column">
            <img src="{{ .image1 }}" style="width:100%" onclick="openModal();currentSlide(1)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image2 }}" style="width:100%" onclick="openModal();currentSlide(2)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image3 }}" style="width:100%" onclick="openModal();currentSlide(3)" class="hover-shadow cursor">
        </div>
        <div class="column">
            <img src="{{ .image4 }}" style="width:100%" onclick="openModal();currentSlide(4)" class="hover-shadow cursor">
        </div>
    </div>
{{ end }}

This works, but how can I access or print out kettenbeil and suerior-attack? The same code. :sweat_smile:

edit: wrong code.. now right

I’d likely map it if I faced the same problem. This would allow you to do multiple values and you wouldn’t have to add more HTML or even JS to add or modify a picture. It would also simplify your toml. For instance:

TOML:

[params]
[params.logos]
[[params.logos.inexoarablez]]
id = 1
title = "Inexoarablez #1"
thumb = "/path/to/thumbnail"
image = "/path/to/full/image"
[[params.logos.inexoarablez]]
id = 2
title = "Inexoarablez #2"
thumb = "/path/to/thumbnail"
image = "/path/to/full/image"
[[params.logos.inexoarablez]]
id = 3
title = "Inexoarablez #3"
thumb = "/path/to/thumbnail"
image = "/path/to/full/image"
... (repeat for other logo sections you need to setup)

Then for your html/shortcode you can just range using the values of each map entry:

<div class="row">
{{ range .Params.logos.inexoarablez }}
<div class="column">
<img src="{{ .thumb }}" style="width:100%" onclick="openModal();currentSlide({{ .id }})" class="hover-shadow cursor">
</div>
{{ end }}
</div>

Then later for your modals:

{{ $currentpage := . }}
<div class="modal">
...
{{ range .Params.logos.inexoarablez }}
<div class="mySlides">
<div class="numbertext">{{ .id }} / {{ len $currentpage.Params.logos.inexoarablez }}</div>
<img src="{{ .image }}" style="width:100%">
</div>
{{ end }}
...
</div>

You can either tailor your Javascript modals by doing an index shift of -1 to match the id key of the map entries, or you may even be able to just have the function call pipe in the path to the image and just sling {{ .image }} into it instead of {{ .id }}. I’m not that good at Javascript so I likely don’t have the qualifications required to tell you the proper way to do this.

I didn’t get a chance to ram this through a Hugo instance of mine, but it theoretically should work at least by my understanding of it.

If all three of your sets are 1:1 related you can put them into the same map entries as well, just the naming conventions of said keys would get a little strange:

[params]
[[params.logos]]
title = "Title #1"
inexoarablezThumb = "/path/to/thumbnail"
inexoarablezImage = "/path/to/full/image"
kettenbeilThumb = "/path/to/thumbnail"
kettenbeilImage = "/path/to/full/image"
superiorattackThumb = "/path/to/thumbnail"
superiorattackImage = "/path/to/full/image"
[[params.logos]]
title = "Title #2"
inexoarablezThumb = "/path/to/thumbnail"
... (continue for rest of icons)

Then in your range contexts, you can reference each icon a key is for, for example {{ .inexoarablezThumb }} instead of just {{ .thumb }}

Sorry, this was really long but when you’re using {{ with … }} or {{ range … }} codeblocks, it changes the context of the leading “.” to the item within it instead of the page.

So if you need to reference the page context inside of one, you need to set a variable before it first, like currentpage, like {{ $currentpage := . }}. Then after that within a with or range block you can access the page context by calling the context on that object like {{ $currentpage.Params… }}

I hope this is useful.

Thanks for your anwser.
Now, I have got a problem with javascript :sweat_smile:

If I click on an image, I always get the first gallery. I know, that has something to do with the id’s. And I call the script three times. But I do not know, how to fix that.

My js:

  // Open the Modal
  function openModal() {
    document.getElementById("myModal").style.display = "block";
  }

  // Close the Modal
  function closeModal() {
    document.getElementById("myModal").style.display = "none";
  }

  var slideIndex = 1;
  showSlides(slideIndex);

  // Next/previous controls
  function plusSlides(n) {
    showSlides((slideIndex += n));
  }

  // Thumbnail image controls
  function currentSlide(n) {
    showSlides((slideIndex = n));
  }

  function showSlides(n) {
    var i;
    var slides = document.getElementsByClassName("mySlides");
    var dots = document.getElementsByClassName("demo");
    var captionText = document.getElementById("caption");

    // If the user clicks on the image, open the modal
    // and show the current slide
    if (n > slides.length) {
      slideIndex = 1;
    }

    
    if (n < 1) {
      slideIndex = slides.length;
    }

    // Hide all slides
    for (i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
    }

    // Hide all dots
    for (i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace(" active", "");
    }

    // Show the current slide
    // and add an "active" class to the thumbnail image
    // that is clicked
    // Show the current slide
    // and add an "active" class to the thumbnail image
    // that is clicked
    slides[slideIndex - 1].style.display = "block";
    dots[slideIndex - 1].className += " active";
    captionText.innerHTML = dots[slideIndex - 1].alt;
  }

  // Close the modal when the user clicks anywhere outside of it
  window.onclick = function (event) {
    if (event.target == document.getElementById("myModal")) {
      closeModal();
    }
  };

my new md (toml):

title = "Logos"

[params]
[params.logos]
[[params.logos.inexorablez]]
id = 1
title = "Inexoarablez #1"
thumb = "/images/logos/inexorablez/inexorablez-01-thumb.webp"
image = "/images/logos/inexorablez/inexorablez-01.webp"
[[params.logos.inexorablez]]
id = 2
title = "Inexoarablez #2"
thumb = "/images/logos/inexorablez/inexorablez-02-thumb.webp"
image = "/images/logos/inexorablez/inexorablez-02.webp"
[[params.logos.inexorablez]]
id = 3
title = "Inexoarablez #3"
thumb = "/images/logos/inexorablez/inexorablez-03-thumb.webp"
image = "/images/logos/inexorablez/inexorablez-03.webp"


[[params.logos.kettenbeil]]
id = 1
title = "Kettenbeil #1"
thumb = "/images/logos/kettenbeil/kettenbeil_logo_01_thumb.webp"
image = "/images/logos/kettenbeil/kettenbeil_logo_01.webp"
[[params.logos.kettenbeil]]
id = 2
title = "Kettenbeil #2"
thumb = "/images/logos/kettenbeil/kettenbeil_logo_02_thumb.webp"
image = "/images/logos/kettenbeil/kettenbeil_logo_02.webp"
[[params.logos.kettenbeil]]
id = 3
title = "Kettenbeil #3"
thumb = "/images/logos/kettenbeil/kettenbeil_logo_03_thumb.webp"
image = "/images/logos/kettenbeil/kettenbeil_logo_03.webp"


[[params.logos.superiorAttack]]
id = 1
title = "Superior-Attack #1"
thumb = "/images/logos/superior-attack/superior-attack-01.png"
image = "/images/logos/superior-attack/superior-attack-01.png"
[[params.logos.superiorAttack]]
id = 2
title = "Superior-Attack #2"
thumb = "/images/logos/superior-attack/superior-attack-02.png"
image = "/images/logos/superior-attack/superior-attack-02.png"

my new html:

<div class="row">
  {{ range .Params.logos.inexorablez }}
    <div class="column">
      <img src="{{ .thumb }}" style="width:100%" onclick="openModal();currentSlide({{ .id }})" class="hover-shadow cursor">
    </div>
  {{ end }}
  </div>

{{ $currentpage := . }}
<div id="myModal" class="modal">
  <span class="close cursor" onclick="closeModal()">&times;</span>
  <div class="modal-content">

  {{ range .Params.logos.inexorablez }}
    <div class="mySlides">
      <div class="numbertext">{{ .id }} / {{ len $currentpage.Params.logos.inexorablez }}</div>
      <img src="{{ .image }}" style="width:100%">
    </div>
  
    <a class="prev" onclick="plusSlides(-1)">&#10094;</a>
    <a class="next" onclick="plusSlides(1)">&#10095;</a>

    <div class="caption-container">
      <p id="caption"></p>
    </div>

    
    <div class="column">
      <img class="demo cursor" src="{{ .image }}" style="width:100%" onclick="currentSlide({{ .id }})" alt="Nature and sunrise">
    </div>
    {{ end }}
  </div>
</div>

my repo:
github repo

At the moment I call the script three times, but I want it in a separate file and call it once. Maby someone can help me.

Have a look at the console in your browser’s developer tools. Perhaps it tells you where your code fails.

Also, lookup classList on MDN and use it’s methods instead of className.

That does look a lot cleaner and more readable to me at least. Good work.

I’m no Javascript expert, there maybe someone more advanced than I am. But I don’t think the className would work out too well. That’s typically an attribute that’s specified for JSX or TSX if you were writing React JS.

You should theoretically use the classList function as @chrillek mentioned. You can call its subfunctions to add and remove classes on demand. For instance to add an “active” class:

item.classList.add("active")

And then to remove it:

item.classList.remove("active")

At least that’s what I see more in of in the wild when looking at vanilla js.

Thanks.. I will have a look on it tomorrow.
What I do not understand is, how can I get a parameter/function from for example inline js onclick= openModel() or currentSlide(id) in a separate file.

If the js file is parsed before the DOM of the HTML is loaded, it can mess with the way it functions, as far as not being able to use document.getElementById(“…”) properly.

To mitigate this you can add the defer attribute to the script tag that sources from the file.

...
<script src="/path/to/js/file" defer></script>
...

This should make it so that the js file is parsed after the DOM is loaded.

Parsing the file shouldn’t matter. Trying to execute the code does. Which you can postpone with a DOMContentLoaded handler.
Exactly what the OP did.

If I do this for example:

html:
<img src="{{ .thumb }}" onclick="test();" >

js separate file(main.js):

function test() {
alert(“test”);
}

it is not executing. How can I access the function?

Your question has nothing to do with Hugo. Even if it had, from you input it is impossible to tell why what you try to do is not working.

And in 2025, you should not use event handlers in your HTML anyway.

I cloned your repo locally to play around with it, I hope you don’t mind.

I do agree with what @chrillek said in the most recent reply, event handlers inside of HTML is generally bad practice. It’s much better to assign an id attrib to it, const it in the JS using const id = document.getElementById("id"), then in a line or two under that call the const to add the event handler on it like id.addEventListener("click", function)

I added a function test() which console logs “blah” similar to what you did, and tried calling it via an anchor tag with the onclick attrib. And got the following in my web browser’s console:

I think it has something to do with defining the code inside of the anonymous function you’re calling using a document/window eventhandler on the DOMContentLoaded event. This won’t make said functions available to event calls inside of the HTML.

Instead I gave the test a tag an id of “test-id1”:

And then brought it into the js by declaring it as a const, then adding its event handler after that:

And then got the intended result doing it that way. Also as @chrillek said, it’s not necessarily Hugo related stuff here so you may get better answers from communities dedicated to HTML and JS.

OK sorry, I know :sweat_smile:

I will ask somewhere else. Do you can suggest a html/js forum or community? But please no stackoverflow… I going to google now.

Thanks for your help and time!!

There are tons of books and online information on JS and HTML out there. Mozilla developer network is a good reference. And keep in mind that you can’t call functions hidden inside other functions from the outside. So this

document.addEventListener('DOMContentLoaded', () => {
  function bla() {
    alert('foo');
 }
}))
bla();

will not work, since bla is not visible outside your event listener. This is basic JS stuff, therefore I said you should go and read about it first before you hurt yourself coding advanced things.