How to add a class attribute to a menu item?

I’d very much like to add a class to a menu item, but it seems it’s not supported, either. Is there a chance that the menu system could allow more attributes such as class? Thank you!

Hello,

You can conditionally assign a class to a menu item directly in a template. Or use any of the menu configuration variables (like for example .Name) to assign a class through the project config or a content file’s front matter.

Also see: https://gohugo.io/templates/menu-templates/#readout

1 Like

Thank you! That’s exactly what I have been doing for a few years in some of my themes, e.g., https://github.com/yihui/hugo-prose/blob/87eb62b0ed8d2515e6088e179879e3f010053c50/layouts/partials/header.html#L23-L27

  {{ range .Site.Menus.main }}
  <li{{ if .Identifier }} class="optional"{{ end }}>
    <a href="{{ .URL }}>{{ .Name }}</a>
  </li>
  {{ end }}

But the hack looks awkward. In the above case, I add a class optional when the identifier is given, but that’s not what identifier is supposed to mean. I’d like to use the otherwise obvious option .Classs, e.g.,

  {{ range .Site.Menus.main }}
  <li class="{{ .Class }}">
    <a href="{{ .URL }}>{{ .Name }}</a>
  </li>
  {{ end }}

instead of hacking at the limited number of existing variables.

For the purpose of CSS styling, the class would be much more useful than identifier, so I wish it could be supported in the future.

This is a new feature request.

May I suggest that you open a new issue with the Proposal tag at: https://github.com/gohugoio/hugo/issues

To backup your request I also suggest that you explain your use case.

1 Like

Can I weigh in here? People always ask “how can I add SOMETHING_I_LIKE to the menu as class” and that is the wrong approach imho :wink: Why not saying: Create a proper navigation template and use the lowercased identifier of the menu point to apply a class.

class="{{ .Identifier | lower }}

You all are having it already up there in the samples. Identifier is a string without spaces. Lowercase it and use that as your class. Add a “mymenu-” before it if you need an identifier-identifier :wink:

If I am not mistaken then if no identifier is given the title is taken and somehow spaces removed.

But what if users also want an id?

<li id="{{ .Identifier }}" class=???>

Then you can probably say, you still have .Pre and .Post, and you can hack at them:

<li id="{{ .Identifier }}" class="{{ .Pre }}">

Then say if I also want, uhm, style.

<li id="{{ .Identifier }}" class="{{ .Pre }}" style="{{ .Post }}">

Until you use up all possible variables :slight_smile: So the actual problem is the limited number of variables. With this limitation, you may be forced to hack. This may also cause inconsistency between themes, e.g., one theme author may use .Identifier for class, and the other theme may use it for id. Then for users, when they want to switch themes, they’d have to learn what these variables mean in a specific theme.

If the Hugo developers (@bep) don’t want to support a specific new variable such as .Class in the menu, perhaps just a new .Params variable that allows theme authors to use arbitrary data from it.

menu:
  main:
    name: "Home"
    identifier: "home"
    params:
      foo: 1
      bar: "whatever"
      class: "optional"

For me, I only wish I could specify classes for specific menu items, so if .Class is supported (this has been the main challenge to me in the menu system), I’ll be all happy. If not, I’ll just resort to the hacks mentioned above.

Thank you for the discussion!

An ID is an ID and a CLASS is a CLASS.

<li id="{{ .Identifier }}" class="menu-{{ .Identifier }}">

That does not block each other out. Even without the menu- part in front it would be possible to apply. You can use {{ .Identifier }} wherever you want.

Variables can be “re-used”. You don’t use up the variable by calling it.

Then what if I want id’s to be unique to each item, but classes shared by some items, e.g.,

<li id="foo-1" class="group-1">
<li id="foo-2" class="group-1">
<li id="foo-3" class="group-2">
<li id="foo-4" class="group-2">

How to use .Identifier to achieve that? It could be achievable (using functions like findRE), but my point is it will be great if one variable serves one purpose. It’s confusing and sometimes inconvenient to reuse (or abuse) one variable for multiple purposes.

What will make your class-groups be grouped? Being under a certain main menu? Belonging to a certain section? That might help. If it’s an internal page type thing you could create some kind of class="menu-{{.Section}}-{{.Slug}}" thingy. It depends on how your setup is.

The problem is, that you can’t add arbitrary parameters to a menu item via front matter. You could add some kind of menugroup=group1 item to frontmatter in pages that are touched by this, but it might have to be in all of them.

1 Like

I was thinking more of a menu that contains items independent to posts, e.g.,

- name: Github
  url: https://github.com
  class: octocat

But you have brought up a great idea—I had never thought of using $.Params (or $.Slug/$.Section) in the range loop to access the parameters of single pages. I totally forgot that I still had access to upper level variables. I really appreciate this tip! This has given me a lot more freedom to customize the menu items. Thank you so much!

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