How would you pass a class to markdown?

Sometimes, I have md content I wish I could tag it with a certain css class.

I would want this output:

div.someclass
   ul
      li foo
      li bar

given this input (or similar)

.someclass
  - foo
  - bar

or

div.someclass
  hello world!

from

.someclass
hello world!

You think something like this is possible feasible?

This is not possible.

Yet, you can make a shortcode which converts markdown within <div /> to HTML.

I tried that, but was not sure, if it was the best approach.

However my shortcode

<div class="gallery">
    {{.Inner}}
</div>

given this md

{{% gallery %}}
- ![](some.png)
- ![](other.png)
{{% /gallery %}}

renders as

<!-- raw HTML omitted -->
<ul>
<li><figure> ...
</ul>
<!-- raw HTML omitted -->

Ah right, as in https://tangenttechnologies.ca/blog/hugo-shortcodes/, this

 [markup]
   [markup.goldmark.renderer]
     unsafe=true

needs to be in config.toml

You can also build a simple markdownify shortcode:

{{ $optBlock := dict "display" "block" }}
{{ with .Inner }}{{ . | $.Page.RenderString $optBlock }}{{ end }}

Another idea is a html-tag shortcode like this (I have not tested this recently):

{{ $optBlock := dict "display" "block" }}
{{ print "<" | safeHTML }}{{ .Get "tag" | default "div" }}{{ with .Get "id" }} id="{{ . }}"{{ end }}{{ with .Get "class" }} class="{{ . }}"{{ end }}{{ with .Get "style" }} style="{{ . | safeCSS }}"{{ end }}{{ print ">" | safeHTML }}
{{ with .Inner }}{{ . | $.Page.RenderString $optBlock }}{{ end }}
{{ print "</" | safeHTML }}{{ .Get "tag" | default "div" }}{{ print ">" | safeHTML }}

This sounds very interesting!
How would I consume this code in md? Or could you point to where I could read about this? https://gohugo.io/functions/markdownify/ isn’t very verbose, I am afraid …

Hi!

Here are two examples:

<div class="my-class-name">
{{< markdownify >}}
# Heading

- list item
- list item
{{< /markdownify >}}
</div>
{{< html-tag tag="section" class="my-class-name" >}}
# Heading

- list item
- list item
{{< /html-tag >}}
2 Likes

Also note that your ā€œgalleryā€ shortcode didn’t work because you called it using {{% %}}. When shortcode should preserve raw HTML, it should be called using {{< >}}, and, in your case, using markdownify or RenderString to process .Inner as markdown.

So, I’m brand new to Hugo. It’s 2026, and things may have changed here but..

It strikes me that once you’ve set unsafe=true the parser will let just about anything through, and you can just add HTML directly to the markdown and it passes. And in the case of my use - for a coloured paragraph of highlighted text - that’s actually shorter than the short code in terms of input and overall codebase…

Input Markdown

## Paragraph

Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.

<p class="danger">This is DANGER text with \*\*bold\*\*, \*italic\* and \~\~strikethrough\~\~ demonstrated.</p>

Output HTML

<h2 id="paragraph">Paragraph</h2>
<p>Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.</p>
<p>Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.</p>
<p class="danger">This is DANGER text with **bold**, *italic* and ~~strikethrough~~ demonstrated.</p>

<p class="danger"></p> = 17 chars

A well named short code would be similar to:

{{< p-danger >}}{{< /p-danger >}} = 33 chars + the needed HTML.

Seems like the minimalist solution here is to enable unsafe parsing and call it a day?

As commented above, use Markdown attributes… no need for a shortcode and no need to allow HTML in Markdown.

2 Likes

Ah, none of the comments above lead to markdown attributes. They lead to another support post which leads to the idea of shortcodes and also the goldmark custom attributes which only supports headings and then continues on the shortcodes train.

Your response is a much welcomed addition to the thread as it feels like a proper answer and solution.

Yeah, support for Markdown attributes with block elements was added on Feb 8, 2021, well after the last comment in this thread. Note that support for Markdown attributes with headings (also a block element) has been around much longer. Some additional examples here.

1 Like

Thanks!

Somewhat related here - when you use Markdown attributes - it’s very unclear how to leverage them in a template. If I have customized the blockquote template, how do I get the classes and ID from {.important #cool-tip} in the template for rendering?

Do they get put into some sort of sensibly named variables like class and id? Seems to be nothing covering this gap in the docs.

I don’t understand the question. This:

This is a paragraph.
{class="foo bar" id="baz"}

Is rendered to this:

<p class="foo bar" id="baz">This is a paragraph.</p>

the classes are automatically added to the html element.

I doubt that there is a template method to retrieve them back.

just style them with CSS selectors.

why do you want te get them back in your template?

That works fine, unless I was to override a template for say, the <p> tag in your example. That I wouldn’t do - but customizing the blockquote tag for the sake of supporting Markdown Alerts is common.

However I want to support the use of {.additionalclass} should a user want it on any blockquote, even if it’s not an alert.. and once you’ve overridden the blockquote template you need to then code the output of these Markdown Attributes into the appropriate attributes of the base element.

Yes, so long as the element is not using a custom template - in order for them to be added to the element a custom template the code must retrieve them from wherever they are automatically stored by Hugo/Goldmark and output. I can’t figure out where these are being picked up and stored and thus cannot workout how to get my templates to support this feature. The classes are auto-added to all elements using default templating.

This would be a surprising gap for me, but as I mentioned in the start of this reply (not to be redundant) - the goal is user experience when leveraging the theme…

How would you do that?

Perhaps it’s not possible to override any element, but I was using it as a theoretical in my example to help with understanding the question. I’m still very new to Hugo - I know you can override blockquotes and codeblocks with templates in the _markup folder. That might be all that can be overridden.

See https://gohugo.io/render-hooks/introduction/ for a list of elements that support render hooks.

For an example of a blockquote render hook that accesses the Markdown attributes see the first example here:
https://gohugo.io/render-hooks/blockquotes/#examples

See also https://gohugo.io/render-hooks/blockquotes/#attributes.