ToC with anchors in posts

The best example is github, for example:

There is an anchor to click on it.

How can I achieve it in hugo? I don’t want to use shortcodes. I want to use standard markdown # H1, ## H2 etc.

That’s JavaScript. It reads the heading’s ID and loads a graphic linking to it. Hugo adds the ID by default (see Content Formats | Hugo). The Hugo docs uses such a script, I believe it lives at

Hmm but I am not sure if google will make Vars / Atoms / Agents then.

Not sure if it has to be static vs javascript. Do you know maybe?

No. You’ll need to read the documentation for the systems you use, that is out of scope for Hugo troubleshooting. :slight_smile:

or use a kind of post processing following the links in this link:

@maiki solution to write own simple js is the one which I choose to solve it. I modified it a little to get GitHub effect.

If somebody is interested in about effect you can see it here Clojure Blog . It is simple JS + CSS.


var anchorForId = function (id) {
    var anchor = document.createElement("a");
    anchor.className = "anchor-link";
    anchor.href      = "#" + id;
    anchor.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" version="1.1"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>';
    return anchor;

var linkifyAnchors = function (level, containingElement) {
    var headers = containingElement.getElementsByTagName("h" + level);
    for (var h = 0; h < headers.length; h++) {
        var header = headers[h];
        if (typeof !== "undefined" && !== "") {

document.onreadystatechange = function () {
    if (this.readyState === "complete") {
        var contentBlock = document.getElementsByTagName("article")[0]
        if (!contentBlock) {
        for (var level = 2; level <= 4; level++) {
            linkifyAnchors(level, contentBlock);


article {
    a {
        color: $link;

    h2, h3, h4, h5 {
        &:hover .anchor-link {
            @media screen and (min-width: map-get($grid-breakpoints, "md")) {
                visibility: visible;
        .anchor-link {
            visibility: hidden;
            float: left;
            margin-left: -20px;
            padding-right: 4px;                

I personlly try to avoid JavaScript for this.

This is probably because you do not want to insert a shortcode before/after each heading.

This is another approach

This is the partial header-link.html:

{{ $content := . | replaceRE "(<h[2] id=\"([^\"]+)\">)(.+)(</h[2]+>)" `${1}${3} <a aria-label="header link for ${3}" href="#${2}" class="header-link">#</a>${4}` }}
{{ $content = $content | replaceRE "(<h[3] id=\"([^\"]+)\">)(.+)(</h[3]+>)" `${1}${3} <a aria-label="header link for ${3}" href="#${2}" class="header-link">#</a>${4}` }}
{{ $content | safeHTML }}

And in single.html you can use:

{{ partial "header-link.html" .Content }}

See here.

1 Like

I personlly try to avoid JavaScript for this.


Thanks for alternative solution.

Good question: At first I thought it was just a matter of taste. But it’s a bit more than that.

This seems to be my policy:

  • Use semantic HTML5.
  • Use pure CSS—following a DRY style. (I do not use SASS any more.)
  • Use (vanilla) JavaScript as little as possible, as much as necessary. (CSS3 provides cool stuff that makes at least JS obsolete.)
  • Inline CSS and JS (unless the file sizes are really huge).
  • Use web-optimized, responsive images (I use a shortcode similar to this one.
  • Definitely use Hugo to put it all together and minify everything.

Of course, if JS is necessary, I am happy to use it (or even Vue or React).

All this makes websites extremely fast, easily maintainable, and valid.

This thread inspired me to do this on my site so thanks for posting this @kwladyka. Doing this in an AsciiDoc content file that’s rendered by asciidoctor involves setting one or both of these attributes:


Details are in and

I hope this is helpful to other asciidoctor users.

There is a CSS-only method that is on this forum somewhere and that I use in my theme.

I found the post that explained it the other day but can’t put my finger on it at the moment.

OK, found it: