How to add 'active' class to Hugo?

I would like to add an active class when:

  1. I am on a page
  2. I am on a category page
  3. To the category item in the menu when the post/page in that category is open

My menu is in this format in config.toml

[menu]
[[menu.main]]
    identifier = "Name"
    name = "Name"
    url = "/category/name/"
    weight = number

And my navigation is like this

<ul class="nav-menu">
 {{ $currentPage := . }}
  {{ range .Site.Menus.main }}
    <li class="{{ if $currentPage.HasMenuCurrent "main" . }}active{{ end }}">
     <a href="{{.URL}}">{{ .Name }}</a></li>
  {{ else }}
    <li><a href="{{.URL}}">{{ .Name }}</a></li>
 {{ end }}
</ul>

What am I missing?

Two things.

1) Use .IsMenuCurrent instead of .HasMenuCurrent.

2) In your site configuration, use pageref instead of url (known issue).

 [[menu.main]]
 name = "Foo"
 pageref = "/category/foo/"

 [[menu.main]]
 name = "Bar"
 pageref = "/category/bar/"

 [[menu.main]]
 name = "Baz"
 pageref = "/category/baz/"
2 Likes

Thanks! So, this is how it has worked so far:

  1. On a page - it is not working when I define a different [menu][menu-nav] and assign page links to it. The workaround was to add the menu: nav weight: number to the front matter of every page I wanted in the (footer) navigation and they appeared automatically in the navigation without configuring them in config.toml.
  2. On a category page - works by retaining the code in the config.toml and adding IsMenuCurrent as you suggested.
  3. Highlighting category as active in main navigation when a post is opened - does not work. Adding the frontmatter menu: main makes the post title appear in the navigation. That would mean over 250 entries in the title alone.

I would prefer to define the pages in the config so I can shorten the titles and have the “highlight category when post open” issue work too.

Like @jmooring mentioned there seems to be better ways to handle this now-a-days.

But in the past, @esawertu I’ve handled it like this:

{{ $current := . }}
{{ range site.Menus.nav }}
	{{ $active := or ($current.IsMenuCurrent "nav" .) ($current.HasMenuCurrent "nav" .) }}
	{{ $active = or $active (eq .Name $current.Title) }}
	{{ $active = or $active (eq .URL $current.RelPermalink) }}
	{{ $active = or $active (and (eq .Name "Blog") (eq $current.Section "blog")) }}
		<a class="{{ if $active }}active{{ end }}" href="{{ .URL }}">
			{{ .Name }}
		</a>
{{ end }}
1 Like

@zwbetz that is causing all manors of issues.

You’ll have to tweak it for your setup.

So at the least change

site.Menus.nav

To be

site.Menus.main

Nav should show the footer menu, but your code made the menu appear on the top navigation as well. I am using .page.path in Jekyll to get option 3 to work, but I am not sure what Hugo’s equivalent is.