Headings enclosed on html section tags

Hi:

I’m new to the forum, not so new to Hugo, but still a newbie.

I’m not a programmer, but I have started to code a new theme for an open source project, and I wish to have a table of contents where the hugo section currently being read is highlighted, so the reader knows where he/she is.

My problem: I wish to enclose each heading and all their contents between html <section> tags, because I wish to use the intersection observer to highlight the current hugo section.

I’ve searched and found this post:

I’ve already tried it and it works!.. Sadly not as I need it…

As it is, the code provided encloses h2 headings within divs, and by doing so, it ignores any h3, h4, … section, although they are included within the h2 div tags. So the toc correctly highlights h2 headings, but none of the lower level headings.

I’ve managed to make hugo surround any heading level between divs by editing the render-heading.html into:

{{ if eq .Level 2 }}
    {{ printf "<!-- end-chunk -->" | safeHTML }}
    {{ printf "<!-- begin-chunk data-anchor=%q -->" .Anchor | safeHTML }}

        {{ else if eq .Level 3 }}
        {{ printf "<!-- end-chunk -->" | safeHTML }}
        {{ printf "<!-- begin-chunk data-anchor=%q -->" .Anchor | safeHTML }}

        {{ else if eq .Level 4 }}
        {{ printf "<!-- end-chunk -->" | safeHTML }}
        {{ printf "<!-- begin-chunk data-anchor=%q -->" .Anchor | safeHTML }}

{{ end }}
<h{{ .Level }} id="{{ .Anchor | safeURL }}">{{ .Text | safeHTML }}</h{{ .Level }}>

though the result is that now each section ends where a new heading starts, no matter its level.

That is:

  • I need:
    <section>
    h2
        <section>
        h3
        </section>
    </section>
  • and my new code gives:
    <section>
    h2
    </section>
    <section>
    h3
    </section>

I have edited the template code into:

{{ range (findRE `(?s)<!-- begin-chunk.*?(?:<!-- end-chunk -->|$)` .Content) }}
  {{ $anchor := replaceRE `(?s).+data-anchor="(.+?)".+` "$1" . }}
  {{ $block := replaceRE `(?s)<!-- begin-chunk.+?-->(.+?)(?:<!-- end-chunk -->|$)` "$1" . }}
  {{/* Remove leading and trailing newlines. */}}
  {{ $block = trim $section "\n" }}
  <section id="{{ $anchor }}">
  {{ $block | safeHTML}}
  </section>
{{ end }}

I just changed the html tag from div to section and the variable $section to $block to avoid confusion with the html tag.

Despite the code uses variables and regular expressions that I still don’t completely understand, I specifically have no idea where the begin-chunk and end-chunk come from. Moreover, I have no clue why the html comment codes are used at all.

I guess such code must need to be expanded with nested variables, functions or new regular expressions, but no matter how hard I’ve searched, I haven’t found any documentation, tutorial or example that helps me.

I’m not looking for someone to send me the correct code (that would be warmly welcomed, though). Instead, what I’m looking for are links or explanations to know how to code it myself. That way I will be able to find solutions to future problems for myself.

Would anybody be kind to lead me in the right direction, please?

Thanks

You could use a Page.Scratch in your render_heading.html to remember the last level and add section start/end tags depending on that and the current level.

However, your approach seems to be a bit brute force. Headings can happen everywhere, not just in content (think navigation, aside sections etc.). Your render_heading template would treat the all the same.

A list or single template might be a better place to deal with the section logic – and it’s also a lot easier there, I guess.

1 Like

Thanks. I will think about this and try to figure out the code.

If you mean that it will add a couple extra tags on each heading, well, yes. But I don’t see that as a bad behaviour, though.

Depending on where you read about this, it is advised or not using sections to enclose headings and its related content. E.g., even though it’s an old document, the W3C talking about html5 sections and ARIA seems to suggest it’s a good practice for accesibility (I may be wrong). So, following that explanation simply adding opening and closing html section tags is not bad per se, as they are officially included in html5 and won’t harm the document. If only included and not used for anything, I guess you’re adding some kbytes to the html page for nothing.

On the other hand, in my template all navigation elements (including the page toc) are simply list elements with some css styling. I have no aside, though, so I can’t say for sure it won’t be a problem there.

Be it as it may, I will also consider using custom code in the list or single template.

Thanks again.

P.S.: and even if I can’t figure out the code I need, I still can use the current custom code I showed in this thread, because with it I can highlight the current heading without gaps, in case of long documents. It’s just that I wish to highlight the current h2 heading AND the current lower level heading being read.

No, that’s not what I mean. But: using a heading render hook for that might add sections at places where they do not belong. For example, I use several h2 headings in an aside – and those should definitely not be enclosed in section tags.

In any case, it would be easier to see what you’re after and offer suggestions if you posted a link to your repository. For example, I don’t really understand if you want to highlight the TOC entries referring to the currently visible content or the content itself or both. In the first case (highlight the TOC entries), why would you even need the sections for the intersection observer? The observer could react on the headings only.

Ok, fine. I will seriously consider adding code into the single template. Thing is I just don’t know how. I’ll figure it out.

Erm… Sorry, no repository. I’m not a programmer and I have yet no clue about git. I’m still learning Hugo and slowly building a theme, so I’m working on a local server and a repo is not yet considered.

But I can share the code here or upload screenshots, which is what I’ll do now.

About the intersection observer: a web browser sees everything on a webpage as blocks, rectangles with content inside. The intersection observer, among other things, is able to know when a certain block is visible on the viewport (on screen), so a script can do things when that block is visible. If the block goes out of view, then nothing can be done depending on that block because is no longer visible.

All of this is important because the block surrounding the heading tags sooner or later will get out of view, so the intersection observer can no longer tell the script to highlight the toc element.

The problem has been shown in the post preceding the one I linked in my first post here: watch the toc and you will see that there are points where no toc element is highlighted. That’s because at that point there are no headings visible on screen. I already saw that problem time ago, but didn’t found any solution to it.

Here you can see my current theme (with a bare-bones style applied to it) and what I wish to have in my page toc (the highlights have been added by hand with the browser dev tools):

The text is in Spanish, but that is not important. You can see an h3 on screen (hugo section number 5.1). With the original code from @jmooring I can highlight the whole h2 section, because the div (or section) surrounds everything up to where the next h2 appears. That’s one thing I need.

With my custom code I would be able to highlight the first h3 heading in the toc, but not the h2 heading (let’s say the h2 heading is no longer visible on the viewport; it currently really is because the upper quote is contained in the h2 section, but if you scrolled down a bit more, then the h2 block will no longer be on screen).

And this is really what I want to accomplish:

Here, the h2 block is yet highlighted, because it still surrounds everything up to the next h2 heading. AND the current visible block is also highlighted, and is a block that ends where the next h3 heading starts, so no gaps in the highlighting, even if the current h3 heading gets out of view.

Hope this helps.