Active Links in Menu

I am trying to set an active class on the current page menu item. I have my menu setup in config.toml

[[menu.main]]
    name = "Home"
    weight = 1
    identifier = "home"
    url = "/"
[[menu.main]]
    name = "Projects"
    weight = 2
    identifier = "projects"
    url = "/projects/"

In my navigation.html partial I have a conditional

<nav>
    {{ $currentPage := . }}
    {{ range .Site.Menus.main }}
      <a class="nav-links{{if or ($currentPage.IsMenuCurrent "main" .) ($currentPage.HasMenuCurrent "main" .) }} active{{end}}" href="{{.URL}}">{{ .Name }}</a>
    {{ end }}
</nav>

However, the first item in the menu “Home” is highlighted and it gets the class of active, but when I click on any other page, those links don’t get the active class. The home does lose the class when it’s not active.

I am still confused, the documentation isn’t that clear on Hugo. I would like to understand this better.

Thanks

I got it, the front matter had to be updated instead of putting them in the config file

This works for me (the classes come from Tachyons):

<nav id="main-nav">

  {{ $page := .Page }}
  {{ $site := .Site }}

  <!-- https://discourse.gohugo.io/t/range-length-or-last-element/3803/3 -->
  {{ $list := .Site.Menus.main }}
  {{ $len := (len $list) }}

  <ul>
    <!-- All pages but the homepage shall have a link to homepage -->
    {{ if not .IsHome }}
      <li class="dib lh-copy"><a class="link underline-hover dim br ph2" href="/">Home</a></li>
    {{ end }}

    {{ range $index, $element := $list }}
      {{ $is := $page.IsMenuCurrent "main" . }}
      {{ $has := $page.HasMenuCurrent "main" . }}
      <li
        {{ if or $is $has }}
          class="li-active dib lh-copy"
        {{ else }}
          class="dib lh-copy"
        {{ end }}>
        <a
          {{ if eq (add $index 1) $len }}
            class="ph2 link underline-hover dim"
          {{ else }}
            <!-- Here it sets a border right unless its last element -->
            class="ph2 link underline-hover dim br"
          {{ end }}
            href="{{ .URL | absURL }}">
          {{ .Pre }} {{ .Name }}
        </a>
      </li>
    {{ end }}
  </ul>
</nav>

And in Front Matter the menu entries look like:

[menu.main]
name = Nav title
weight = 25

[menu.footer]
weight = 10
2 Likes

Thanks

Sorry, but if isn’t in config.toml so where exactly should menu be?

Actually it’s a choice, I am still discovering Hugo. If I don’t mention anything in the config file and just add some front matter in pages like menu: “main”, weight: “2” for example, it still shows up in the top main navigation :slight_smile:

You can put in in config.toml or in Front Matter the same way. Both are discovered by .Site.Menus.main. And you can do both…

Thanks. Can you provide some full example? Because now I’m using in config.toml it renders ok with nested items.
When I put menu item in frontmatter it displays well but I have issues with nested items and checking what item is active now.

In config.toml:

[[menu.main]]
  name = "About"
  weight = -110
  url = "/about"
  identifier = "about"

[[menu.main]]
    name = "Other"
    weight = -110
    identifier = "other"

[[menu.main]]
    name = "Culture"
    weight = -110
    url = "/other/culture"
    parent = "other"

[[menu.main]]
    name = "Contacts"
    weight = -110
    url = "/other/contacts"
    parent = "other"

[[menu.main]]
    name = "FAQ"
    weight = -110
    url = "/other/faq"
    parent = "other"

Changing active from here https://gohugo.io/templates/menu-templates/ doesn’t work

What should I do to make it works? Any suggestion would be great, because my is over for now :frowning:

Perhaps it helps if you browse through my test project: https://legobitbucket@bitbucket.org/legobitbucket/hugo-template.git

Look in partials/site/header.html where you find the code for the menu. In content you can see the Markdown Files with Front Matter Menus.

Most of it is in german but you’ll find your way.

Hope this helps.

Thank you for help. I hope too I’ll find answers

I used JavaScript for this, in case someone looks for the same query I was searching and jumps on this thread:

<script>
(function() {
    const links = document.getElementsByTagName('a')
    const currentUrl = location.href
    for (const link of links) {
        if (link.href === currentUrl) {
            link.classList.add('active')
        }
    }
}())
</script>

It’s possible to do this without JavaScript which is (in my eyes) a better solution, for the following reasons:

  • visitors that have JavaScript turned off will still see the correct result
  • because JavaScript can sometimes be executed later (for network or other reasons) the user will first see the menu without the highlighted current link and then see that link light up once the JavaScript runs.