# Adding captions to images?

**URL:** <https://discourse.gohugo.io/t/adding-captions-to-images/40102>\
**Category:** support\
**Created:** [August 21, 2022, 10:38pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102 "2022-08-21T22:38:28Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 21, 2022, 10:38pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/1 "2022-08-21T22:38:28Z")

</div>

[This comment](https://discourse.gohugo.io/t/new-markdown-attribute-and-render-hooks/40076/9) made me check my images source code and indeed there are broken paragraph tags! I use `<figure>` to present a caption with `<figcaption>`, but my images are in markdown format `![image title](img-link "image caption")`. So, which is the correct way to add captions in Hugo, without having to convert hundreds of images to shortcodes?

---

<div class="post-metadata">

**Author:** ![gaetawoo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/gaetawoo/32/16789_2.png) [@gaetawoo](https://discourse.gohugo.io/u/gaetawoo)\
**Post date:** [August 22, 2022, 2:57am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/2 "2022-08-22T02:57:06Z")

</div>

In your render-image.html use .Title in the figcaption tag.

---

<div class="post-metadata">

**Author:** ![Mehdi\_Saada](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/mehdi_saada/32/16885_2.png) [@Mehdi\_Saada](https://discourse.gohugo.io/u/Mehdi_Saada)\
**Post date:** [August 22, 2022, 7:21am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/3 "2022-08-22T07:21:36Z")

</div>

I did that and someone still complained it would break paragraphs, how ?

```auto
<figure>
   <figcaption><p>{{ with .Title }} {{ . | markdownify }} {{ end }}
   </p></figcaption>
 <a href="{{ .Destination | safeURL }}" target="_blank">
<img src="{{ replace .Destination ".jpg" ".jpg.small" | safeURL }}" alt="{{ .Text }}"
{{ with .Title }}title="{{ . }}"{{ end }}/>
</a>
</figure>

```

---

<div class="post-metadata">

**Author:** ![chrillek](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/chrillek/32/19797_2.png) [@chrillek](https://discourse.gohugo.io/u/chrillek)\
**Post date:** [August 22, 2022, 7:31am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/4 "2022-08-22T07:31:22Z")

</div>

> [@Mehdi\_Saada](#):
>
> it would break paragraphs, how

The problem arises when you use an image _inline_, i.e. somewhere in the middle of your text. If the image forms its own paragraph (i.e. with an empty line before and after it), your `figure` approach should be fine.

---

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 22, 2022, 9:12am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/5 "2022-08-22T09:12:53Z")

</div>

I am using a modified version of [this code](https://discourse.gohugo.io/t/simple-image-render-hook-template-for-responsive-images/22464) (using `<picture>` tag wrapped in `<figure>` tag). So it already uses the `.Title` as caption. (I removed the figure and placed the caption as a span, but I had to make the image a block element with CSS `display: block`),

---

<div class="post-metadata">

**Author:** ![gaetawoo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/gaetawoo/32/16789_2.png) [@gaetawoo](https://discourse.gohugo.io/u/gaetawoo)\
**Post date:** [August 22, 2022, 11:15am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/6 "2022-08-22T11:15:21Z")

</div>

It’s not clear what your problem is with the figcaption.

And instead of block you could use inline-block on the container of the image and caption.

---

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 22, 2022, 11:37am UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/7 "2022-08-22T11:37:21Z")

</div>

Please revisit the comment I linked by JOE.

---

<div class="post-metadata">

**Author:** ![gaetawoo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/gaetawoo/32/16789_2.png) [@gaetawoo](https://discourse.gohugo.io/u/gaetawoo)\
**Post date:** [August 22, 2022, 12:28pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/8 "2022-08-22T12:28:36Z")

</div>

Oh, I see… well I can’t help with the HTML spec. Each paragraph or new line in markdown is rendered as a `<p></p>` so no matter what you do in markdown syntax, that’s going to happen. If you want valid HTML then you need to use a shortcode to render the figure. A solid search/replace using regex could probably make changing all your content pretty painless.

Alternately, and I don’t know if this would work… is when you place the rendered content in your layouts {{ .Content }}, you could do a search and replace there to strip any immediate paragraph tags before and after a figure tag. That’s just a work around though, not best practice.

---

<div class="post-metadata">

**Author:** ![gaetawoo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/gaetawoo/32/16789_2.png) [@gaetawoo](https://discourse.gohugo.io/u/gaetawoo)\
**Post date:** [August 22, 2022, 12:37pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/9 "2022-08-22T12:37:09Z")

</div>

But you could also wrap the img and caption p in an inline-block div. Then it is still inline with the rest of the document. And the image and caption are aligned. Another workaround

---

<div class="post-metadata">

**Author:** ![gaetawoo](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/gaetawoo/32/16789_2.png) [@gaetawoo](https://discourse.gohugo.io/u/gaetawoo)\
**Post date:** [August 22, 2022, 1:35pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/10 "2022-08-22T13:35:07Z")

</div>

I made this a while ago while learning about the similar thing:  
https://codepen.io/gaetawoo/embed/preview/MWQeJzX?default-tabs=html%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=MWQeJzX

---

<div class="post-metadata">

**Author:** ![jmooring](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jmooring/32/4214_2.png) [@jmooring](https://discourse.gohugo.io/u/jmooring)\
**Post date:** [August 22, 2022, 3:39pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/11 "2022-08-22T15:39:08Z")

</div>

> [@chrillek](#):
>
> The problem arises when you use an image _inline_, i.e. somewhere in the middle of your text. If the image forms its own paragraph (i.e. with an empty line before and after it), your `figure` approach should be fine.

This is false. [Try it](https://spec.commonmark.org/dingus/?text=!%5BKitten%5D(https%3A%2F%2Fplacekitten.com%2F50%2F50)%0A%0AImage%20!%5BKitten%5D(https%3A%2F%2Fplacekitten.com%2F50%2F50)%20and%20text).

In both cases the image (or whatever the image render hook produces) is wrapped within a `p` element.

> [@gaetawoo](#):
>
> But you could also wrap the img and caption p in an inline-block div

This would still produce invalid HTML. You cannot place a `div` element within a `p` element.

> [@tut](#):
>
> So, which is the correct way to add captions in Hugo

To produce semantically accurate and accessible HTML, use the embedded [figure shortcode](https://gohugo.io/content-management/shortcodes/#figure) or create your own.

---

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 22, 2022, 4:06pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/12 "2022-08-22T16:06:43Z")

</div>

> [@jmooring](#):
>
> To produce semantically accurate and accessible HTML, use the embedded [figure shortcode](https://gohugo.io/content-management/shortcodes/#figure) or create your own.

Again, with hundreds of images, I want to avoid this and stick with markdown syntax as closely as possible. So, for now, I will use the span element I implemented and some CSS to align everything as required.

---

<div class="post-metadata">

**Author:** ![jmooring](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jmooring/32/4214_2.png) [@jmooring](https://discourse.gohugo.io/u/jmooring)\
**Post date:** [August 22, 2022, 4:08pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/13 "2022-08-22T16:08:35Z")

</div>

I obviously have an opinion about the _right_ way to do this given the availability of the `figure` element in HTML5, but using `span` elements in conjunction with the `aria-labelledby` attribute will produce accessible, valid HTML.

So I think you are on the right track.

---

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 22, 2022, 4:12pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/14 "2022-08-22T16:12:02Z")

</div>

No doubt. But I want to future-proof the content in case my team makes a decision to switch to another SSG (not happening, but just in case. I co-author one site with a team). I don’t want to be left with hundreds of shortcodes I will have a nightmare to fix.

> [@jmooring](#):
>
> but using `span` elements in conjunction with the `aria-labelledby` attribute will produce accessible, valid HTML.

Nice idea! I will look into it further.

---

<div class="post-metadata">

**Author:** ![chrillek](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/chrillek/32/19797_2.png) [@chrillek](https://discourse.gohugo.io/u/chrillek)\
**Post date:** [August 22, 2022, 4:57pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/15 "2022-08-22T16:57:29Z")

</div>

> [@jmooring](#):
>
> This is false. [Try it](https://spec.commonmark.org/dingus/?text=!%5BKitten%5D(https%3A%2F%2Fplacekitten.com%2F50%2F50)%0A%0AImage%20!%5BKitten%5D(https%3A%2F%2Fplacekitten.com%2F50%2F50)%20and%20text).

What exactly is “false”? In the 2nd case, the image is not “wrapped” inside a paragraph, it is simply part of that paragraph as an inline element. In the first case, it is indeed wrapped in the paragraph, i.e. the `p` element is added kind of out of nowhere. Or rather: the markdown processor adds it because there’s a blank line after the image.

> [@jmooring](#):
>
> > [@gaetawoo](#):
> >
> > But you could also wrap the img and caption p in an inline-block div
> 
> This would still produce invalid HTML. You cannot place a `div` element within a `p` element.

I beg to differ. Wrapping a `div` around an `img` and a `p`, as @gaetawoo suggested, should be fine. They did not suggest putting the `div` inside the `p`.

```html
<div>
  <img...>
  <p class="caption">
</div>

```

That was actually the suggested approach before `figure` came along.

---

<div class="post-metadata">

**Author:** ![jmooring](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jmooring/32/4214_2.png) [@jmooring](https://discourse.gohugo.io/u/jmooring)\
**Post date:** [August 22, 2022, 5:01pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/16 "2022-08-22T17:01:50Z")

</div>

> [@chrillek](#):
>
> In the 2nd case, the image is not “wrapped” inside a paragraph, it is simply part of that paragraph as an inline element.

I think I am not communicating very well.

In both cases the image (or whatever the image render hook produces) is within a `p` element, and you cannot place a `figure` or `div` within a `p`.

---

<div class="post-metadata">

**Author:** ![chrillek](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/chrillek/32/19797_2.png) [@chrillek](https://discourse.gohugo.io/u/chrillek)\
**Post date:** [August 22, 2022, 5:05pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/17 "2022-08-22T17:05:18Z")

</div>

I understand. However, I have a image render hook producing a `figure`, and this `figure` is not wrapped in a `p`, although the markdown image code is on its own line. Seems a bit weird, after having read this thread and the old issue on Github.

---

<div class="post-metadata">

**Author:** ![jmooring](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jmooring/32/4214_2.png) [@jmooring](https://discourse.gohugo.io/u/jmooring)\
**Post date:** [August 22, 2022, 5:07pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/18 "2022-08-22T17:07:25Z")

</div>

> [@chrillek](#):
>
> I have a image render hook producing a `figure`, and this `figure` is not wrapped in a `p`

I’d love to see a test repo that demonstrates this.

---

<div class="post-metadata">

**Author:** ![jmooring](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.gohugo.io/jmooring/32/4214_2.png) [@jmooring](https://discourse.gohugo.io/u/jmooring)\
**Post date:** [August 22, 2022, 5:10pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/19 "2022-08-22T17:10:43Z")

</div>

> [@tut](#):
>
> Nice idea! I will look into it further.

Since `.Ordinal` is not available in the image render hook, you’ll need to create the unique element `id` another way.

> **Crude image render hook example**
>
> ```auto
> {{- $id := now.UnixNano | string | add "caption-" }}
> {{- with $caption := .Title | .Page.RenderString }}
> <span class="img-with-caption">
> <img src="{{ $.Destination }}" alt="{{ $.PlainText }}" aria-labelledby="{{ $id }}">
> <span class="img-caption" id="{{ $id }}">{{ $caption }}</span>
> </span>
> {{- else }}
> <img src="{{ .Destination }}" alt="{{ .PlainText }}">
> {{- end }}
> {{- /**/ -}}
> 
> ```

  

> **And the related CSS**
>
> ```auto
> span.img-with-caption {
> display: inline-block;
> }
> span.img-caption {
> float: left;
> text-align: center;
> width: 100%;
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![tut](https://avatars.discourse-cdn.com/v4/letter/t/e95f7d/32.png) [@tut](https://discourse.gohugo.io/u/tut)\
**Post date:** [August 22, 2022, 5:21pm UTC](https://discourse.gohugo.io/t/adding-captions-to-images/40102/20 "2022-08-22T17:21:58Z")

</div>

Since I am generating different image sizes, can the ID be added to the `<picture>` tag instead?

[Next page](https://discourse.gohugo.io/t/adding-captions-to-images/40102.md?page=2)
