Add id and link to each <li> in a list

I have a simple list, where some items may be quite long. For example:

- Lorem ipsum dolor sit amet.
- Ut enim ad minim veniam.
- Ut enim ad irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

I need an HTML output where each item has an id and a link to itself, so that visitors have an easy way to link to them directly. For example:

<ul>
  <li id="foo">Lorem ipsum dolor sit amet. <a href="#foo">#</a></li>
  <li id="bar">Ut enim ad minim veniam. <a href="#bar">#</a></li>
  <li id="bar">Ut enim ad irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. <a href="#bar">#</a></li>
</ul>

I don’t care how the ID is generated, but:

  • it should not be the full li content, because it can be several words long
  • it must be unique, so it can’t just use the first word of the item, because it may repeat in the list
  • it must not be the position in the list, because I may need to add items in the middle of the list without breaking existing links

Writing manually the IDs is acceptable, but I would prefer if it could be done automatically.

Any idea on how this could be done?

We can automatically add id attributes to dt elements within description lists, but we can’t do this with ordered or unordered list items. We use this extensively on our documentation site (e.g., this list item) where the id attribute is added by Hugo, and the anchor is added via JS.

Option A

You might consider adding a markdown attribute to the list as a whole, and link to that. That gets you somewhere close on the page, but is obviously not precise.

Option B

Another option is to simply use the HTML content format, or create a shortcode that renders the raw HTML. Note that this is unsafe unless you control the content.

Option C

Yet another option is to create a link render hook, based on Hugo’s embedded link render hook, that performs special handling of link destinations such as “@”. For example, the Markdown might look like this:

- Item one [foo](@)
- Item two [bar](@)
- Item three [baz](@)

With a render hook that contains something like this:

{{- if eq .Destination "@" }}
  {{- $t := .PlainText | anchorize }}
  <a id="{{ $t }}" href="{{ .PageInner.RelPermalink }}#{{ $t }}">#</a>
{{- else }}
  ...
{{- end -}}

The resulting HTML:

<ul>
  <li>Item one 
    <a id="foo" href="/posts/post-1/#foo">#</a></li>
  <li>Item two 
    <a id="bar" href="/posts/post-1/#bar">#</a></li>
  <li>Item three 
    <a id="baz" href="/posts/post-1/#baz">#</a></li>
</ul>

What you would see in the browser (style anchor elements as needed):

image

We do something similar to this on our documentation site to create links to glossary terms.

2 Likes

Hey, thank you for your answer! The description list could be what I’m looking for. How would I make Hugo add id to dt?

https://gohugo.io/configuration/markup/#parserautodefinitiontermid

Great, thank you!

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.