indicator

Drop Down Menu Indicator

Posted

I think it’s important to give users a visual cue when menu items have a drop down menu.

One way I’ve handled this in the past is to use the Superfish jQuery plugin, which adds a class to any list items with children. This allows them to be styled differently- with a background image of a down arrow (for instance).

menu-example

However, I just saw a new theme released by Paul de Wouters called Spine. Instead of using javascript to apply the class- he uses a custom Walker_Nav_Menu so that the class is added to the markup directly.

I think this is a much better way to do it, and solves an issue I’ve seen in some themes where the menu items shift a bit when the new classes and styling are applied with javascript.

Custom Walker Code

I’ve adapted Paul’s code a little bit so it just adds a “has-children” css class to any top level “li” that has a “ul” contained within it:

class Custom_Nav_Walker extends Walker_Nav_Menu {
	function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
		$id_field = $this->db_fields['id'];
		if ( !empty( $children_elements[$element->$id_field] ) && ( depth == 0 ) ) {
			$element->classes[] = 'has-children'; // Use any classname you like
		}
		Walker_Nav_Menu::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
	}
}

Then, when you call the menu in the theme, make sure to include the walker:

<?php wp_nav_menu( array( 'theme_location' => 'primary', 'walker' => new Visual_Nav_Walker(), 'depth' => '2' ) ); ?>

However, for some reason the above code does not fall back to wp_page_menu properly when no menu is set. So, this is my workaround:

if ( has_nav_menu( 'primary' ) ) {
     wp_nav_menu( array( 'theme_location' => 'primary', 'walker' => new Visual_Nav_Walker(), 'depth' => '2' ) );
} else {
     wp_page_menu();
}

Menu Filter (Updated 3/20/13)

Chip Bennet posted an alternative approach using a filter on wp_nav_menu_objects to the WordPress Theme Reviewers List. This approach seems a bit more straightforward than a walker, so it’s also worth checking out.

Styling the List Item

There’s many ways you could go about styling this list item with the “has-children” class. For a new theme I’ve been working on, I already use glyphs from the Entypo icon font- and I think the “chevron-small-down” from this collection works great as a drop down menu indicator.

To use it with my menu (.main-navigation) I just needed to add this CSS:

.main-navigation li {
     float: left;
     position: relative;
}
.main-navigation li.has-children a {
     padding-right:40px;
}
.main-navigation li.has-children > a:after {
     content:'\e760';
     font-family: 'entypo';
     position: absolute;
     right:20px;
     speak: none;
}

(For more about using icon fonts, see this post)

I’ve also been thinking a “has-children” class might be a good core feature. Any thoughts?

About Devin

I'm a WordPress developer based in Austin, Texas. Follow my projects on GitHub, or more general WordPress ramblings as @devinsays on twitter.

10 thoughts on “Drop Down Menu Indicator

  1. Chip Bennett wrote:

    +1 to pushing this as a patch back to core. I think that’s a great idea.

  2. WPExplorer wrote:

    I’ve always used superfish for my drop-downs which ads the sub item indicator via JS, but this is much better and perfect for CSS only menus – slick!

    Thanks for the share ;)

  3. The custom Nav Walker is really useful. I’ve been using it when creating a WP theme with Bootstrap framework. And not only Bootstrap, but almost every CSS library (like Foundation in Spine theme), they require custom HTML markup for its element, e.g. nav menu.

    This is a good technique, and I think it should be the “official” way to customize the menu.

  4. WPHub wrote:

    Hi Devin,

    Thanks for turning me on to this patch. This is a much better solution than superfish.

  5. CreativeStag wrote:

    Looks much better, thanks for sharing this patch.

  6. Alshe Dupur wrote:

    It’s not work for me.

    This css work for me.

    #navwrap li a:not(:last-child):after {
    content: “\e760″;
    font-family: ‘entypo’;
    padding-left: 0.5em;
    speak: none;
    }

    #navwrap ul ul li a:not(:last-child):after {
    content:’\e762′;
    font-family: ‘entypo’;
    position: absolute;
    right:20px;
    speak: none;
    }

    Note: #navwrap is my menu id.

  7. Thanks for share code. I was looking how to create a drop down menu. Thanks

  8. Luke Etheridge wrote:

    Hey there,

    Is there a way to do this but instead wrap the parent link in a ‘parent’ div IF it has children, and also include a description to the parent if it has one?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>