Skip to main content

How to Add unique classes to Drupal menus

Post to Twitter

Sometimes you want to be able to style menu items individually. For example you may want to use image replacement to display icons instead of the text, or you may want to make one menu item stand out from the rest.

Drupals Primary and Secondary links allow you to do this because they print a class on the li that includes the mlid, so its easy to target a particular link doing something like:

li.menu-123 a {font-weight: bold;}

But, in normal Drupal menus, the ones that appear in blocks, no such classes appear, which leaves them all with the same style.

There is a very good module for getting around this called Menu Attributes, which allows you to specify additional attributes for menu items such as id, name, class, style, and rel. The problem here is that you need an additional module, and if like us, you’re building themes for clients sites you don’t really want to rely on 3rd party modules to be installed and maintained, not for trivial design aspects such as few classes on menu items in any case.

The solution is to override theme_menu_item_link, and add the mlid to the actual link.

Drop this snippet into your template.php file and as per usual, replace themeName with your themes name.

<?php
function themeName_menu_item_link($link) {
  if (empty(
$link['localized_options'])) {
   
$link['localized_options'] = array();
  }
  if (empty(
$link['localized_options']['attributes']['class'])) {
   
$link['localized_options']['attributes']['class'] = 'menu-'. $link['mlid'];
  }
  else {
   
$link['localized_options']['attributes']['class'] .= ' menu-'. $link['mlid'];
  }
  return
l($link['title'], $link['href'], $link['localized_options']);
}
?>

Comments

#1 It’s a nice solution, but if

It’s a nice solution, but if it’s unique, it should be an id, rather than a class. We often take the name of the menu item, run it through some kind of text replacement to strip out all special characters, and use that for the attribute ID. That way, when you look back over your CSS, you know which statement refers to which menu element.

#2 ...

I have other snippets that do that, but I’m not a big fan because end users can change the menu text and thus bork the styling. I agree very much though it does make for highly readable CSS and thats a nice win if menu links are not going to be changed. I might post a follow up with a snippet that does what you describe, thanks for reminding me.

#3 ....

[..]menu links are not going to be changed[..]

Yes but how does this technique fix that? And how would this work if I removed and then added the menu link back, the styling wouldn’t apply and it isn’t clear on the menu UI as to why.

I like Chris’ solution considerably better as it doesn’t rely on the mlid

We often take the name of the menu item, run it through some kind of text replacement to strip out all special characters, and use that for the attribute ID

#4 sigh...

Yes but how does this technique fix that?

Because it uses the mlid and not the actual text. Dude, I have used both methods extensively over the years and fwiw, I’ve found for my clients using the mlid more reliable. Maybe not for you, so do what you want. The link text method has been posted on d.o for over 2 years I believe, but I do not recall seeing this technique posted anywhere, so this is a contribution for those who want to do this (several users asked me about this recently which is why I posted it).

#5 And you can also use (and improve) the module :)

Daniel from Linnovate released the menuclass module that does the exact same thing.
All non coders can check it out at http://www.drupal.org/project/menuclass

#6 how about the whole menu tree?

Today I ran into a problem. I needed to add “first” and “last” class names to the first and the last menu items in a menu and I couldn’t find a solution yet (I only spent one hour searching for a solution, and I guess there is one, but I hope you can point me in the right direction). My menu is a “nice_menus” generated one. I guess I should create a function in my template.php file inside my theme folder, but I couldn’t find a solution yet. Any ideas?

#7 Worked Great

OK, Well I think this is really helfpful and I appreciate it a lot.

I have a question. Why check for localized options? we would not want to write different css for each location… or would we?

i’m guessing you use class instead of node b/c a user might have an instance of the menu in more than one spot?