Exclude parent section from active menu

My menu code is below. All my nested sections are inside the blog section e.g content/blog/news. I am using pageref for the menu link to show and style active menus differently. The menu has a blog item and the second is a sections item with all the nested sections as its children.
I am facing an issue, however, where the blog menu entry appears active when any of the nested items are selected (with both IsMenuCurrent and HasMenuCurrent. I replaced pageref with url for the blog menu item and it works, but I lose the active class for the item when I navigate to the blog section. Is there a way to exclude the active class for the blog section when I click on the nested section, but retain it only when I navigate to the blog section itself?

<ul class="main-menu">
            {{- $currentPage := . }}
            {{- range site.Menus.main }}
            {{- if .HasChildren }}
            <li class="menu-item">
              <a class="menu-link" href="#">{{ .Name }}<span>▾</span></a>
              <ul class="submenu">
                {{- range .Children }}
                <li class="submenu-item">
                  <a href="{{ .URL }}" {{- if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} class="submenu-link active" aria-current="page" {{ end }}>{{ .Name }}</a>
                </li>
                {{- end }}
              </ul>
            </li>
            {{- else }}
            <li class="menu-item">
              <a href="{{ .URL }}" {{- if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} class="menu-link active" aria-current="page" {{ end }}>{{ .Name }}</a>
            </li>
            {{- end }}
            {{- end }}
          </ul>

Unless I’m missing something, this is behaving as expected given your inclusion of the .HasMenuCurrent in the conditionals.

I use it to target single pages within a nested section, where the menu item is active when a post in that section is opened. So, that means there is no workaround for this?

With this menu structure:

[[menu.main]]
name = 'Posts'
pageRef = '/posts'

[[menu.main]]
name = 'Foo'
pageRef = '/posts/foo'
parent = 'Posts'

[[menu.main]]
name = 'Bar'
pageRef = '/posts/foo/bar'
parent = 'Foo'

[[menu.main]]
name = 'Test'
pageRef = '/posts/foo/bar/test'
parent = 'Bar'

The HasMenuCurrent method returns true for all but the current entry when visiting /posts/foo/bar/test. This is useful for setting aria-current="true" on parent items. For example, when visiting /posts/foo/bar/test:

Show HTML
<!-- I believe this follows a11y guidelines -->
<ul>
  <li class="nav-item">
    <a aria-current="true" class="nav-link" href="/posts/">Posts</a>
    <ul>
      <li class="nav-item">
        <a aria-current="true" class="nav-link" href="/posts/foo/">Foo</a>
        <ul>
          <li class="nav-item">
            <a aria-current="true" class="nav-link" href="/posts/foo/bar/">Bar</a>
            <ul>
              <li class="nav-item active">
                <a aria-current="page" class="nav-link" href="/posts/foo/bar/test/">Test</a>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

I suppose you could use menu parameters to flag entries for exclusion, and modify your conditionals accordingly.

My menu structure is like this (in config/_default/menu.toml)

[[main]]
name = "Blog"
pageref = "/blog"
weight = 1

[[main]]
name = "sections"
identifier = "sections"
weight = 2

    [[main]]
        name = "news"
       pageref = "/blog/news"
       weight = 1
      parent = "sections"
      <!-- All other nested sections go here in the same format -->

So, if I understand your solution, I need to add a class entry to the blog menu? How would the conditions look after modifying for example? I was thinking of editing my CSS to exclude the class, but I am curious how your suggestion would look like.

Edit: The class returns an empty string. But using pre with safeHTMLAttr inserts the content as expected.

Edit 2: Somehow, IsMenuCurrent works with pages in the current menu. I could swear when I first tried Hugo, it didn’t work hence why I used HasMenuCurrent. Removing the latter makes the menu’s active class to work as expected. So, that’s out of the way.

Do you need additional assistance?

Maybe on this. Is the class for menus in config file or frontmatter?

site configuration (TOML)

[[menu.main]]
name = 'Test'
pageRef = '/post/test'
weight = 1
  [menu.main.params]
  class = 'foo'

site configuration (YAML)

menu:
  main:
    - name: Test
      pageRef: /post/test
      weight: 1
      params:
        class: foo

template

{{ range site.Menus.main }}
  <a class="{{ .Params.class }}" href="{{ .URL }}">{{ .Name }}</a>
{{ end }}
3 Likes

Thanks! I have been using pre and appending safeHTMLAttr to it in the past. This is much better and I would recommend it goes in that section of the docs.

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