Another way to make a menu item active


#1

I ran into a scenario recently where my menu item would be active when viewing my blog posts list page, but not when viewing an individual blog post.

As an example, let’s say my config.toml menu looks like:

[menu]
  [[menu.nav]]
    name = "Home"
    url = "/"
    weight = 1
  [[menu.nav]]
    name = "Blog"
    url = "/post/"
    weight = 2

The “Blog” menu item is active when viewing the list page URL:

/post/

But not when viewing a single page URL:

/post/some-blog-post/

I solved it checking if the current menu iteration name was “Blog” and if the current section was “post”. I did the same thing for my “Tags” pages. Here’s a stripped down version of the solution:

{{ $current := . }}
{{ range .Site.Menus.nav }}
  {{ $active := or ($current.IsMenuCurrent "nav" .) ($current.HasMenuCurrent "nav" .) }}
  {{ $active = or $active (eq .Name $current.Title) }}
  {{ $active = or $active (and (eq .Name "Blog") (eq $current.Section "post")) }}
  {{ $active = or $active (and (eq .Name "Tags") (eq $current.Section "tags")) }}
  <a href="{{ .URL }}" class="{{ if $active }}active{{ end }}">{{ .Name }}</a>
{{ end }}

Here’s the full nav partial and the full menu config. You can see it in action here by clicking any of the blog posts and noticing the “Blog” menu is still set to active.

If others know of a better way to solve this, please do share.


#2

great tip, thanks man. I’m using this for my blog!


#3

Super elegant way of adding up or clause without impeding readability!
I’ll use this syntax a lot and not only for menu items :slight_smile:


#4

This is one of those examples that is worth adding to the docs, IMHO. Thanks much for sharing!


#5

Would it be possible to explain the logic of the code for those of us who don’t read it like a book?

Also, I am not sure what exactly to look for. What makes the menu look active?

Sorry, still learning.


#6

I’m on my phone so this will be terse.

Mark the menu item as active if the menu item name equals current page title:

{{ $active = or $active (eq .Name $current.Title) }}

Mark the menu item as active if the current menu item name is Blog and the current page section is post:

{{ $active = or $active (and (eq .Name "Blog") (eq $current.Section "post")) }}

Mark the menu item as active if the current menu item name is Tags and the current page section is tags:

{{ $active = or $active (and (eq .Name "Tags") (eq $current.Section "tags")) }}

In the case of the Cupper theme, the menu item will be visually highlighted.


The Free Bundle and HUGO Menu
#7

Note that were you menus config added through individual page’s Front Matter, you could access any Menu item’s page with .Page, and therefor perform more faithful and generic tests than with .Name.

Per example instead of testing the menu item’s .Name against the name of current page’s section, you could compare the sections.

  {{ $active := or ($current.IsMenuCurrent "nav" .) ($current.HasMenuCurrent "nav" .) }}
  {{ $active = or $active (eq .Page $current) }}
  {{ $active = or $active (eq .Page.Section $current.Section)) }}

#8

In my setup, I used comparison of the urls to achieve this. No need for any or clause:

{{ $active := in $current.RelPermalink .URL }}

#9

@kascme I like this way too. But I use the filename for my permalinks so this wouldn’t work in my specific case


#10

True. But if you use path.Dir you should get the menu link marked as active as well:

{{ $active := in $current.RelPermalink (path.Dir .URL) }}

#11

Unfortunately that doesn’t work as expected. This is a screenshot of the menu while on the “Blog” page (only the Blog menu item should be highlighted).

For debugging, I’ve printed the path.Dir for each menu item.


#12

Playing off your syntax, I got the below snippet to work as expected, but I prefer my original way.

{{ $active := or ($current.IsMenuCurrent "nav" .) ($current.HasMenuCurrent "nav" .) }}
{{ $active = or $active (eq .Name $current.Title) }}
{{ $active = or $active (and (eq (trim (path.Dir .URL) "/") $current.Section) (ne $current.Section "")) }}

#13

@ zwbetz: You are right. I had no Home nor any other root link in my menu, so it was working for me. I guess a check if the menu item belongs to Kind section or page would also work. But that’s again adding extra lines. My example above made using .IsMenuCurrent, .HasMenuCurrent obsolete, so it was just a one liner. That’s why I suggested it, but as you pointed out, it is not working for every use case.