Navigation menus are having a bit of a moment in the spotlight. From burger menus for mobile through mega menus for stores to sticky menus for enhanced user experience, there’s a great choice in the way you can present your navigation menu in your WordPress site.
But what if you want to create a straightforward menu with a few top-level items and some more items that drop down from them when the user hovers over them?
Before you start getting into coding advanced menus like mega menus and burger menus, it’s a good idea to learn how to create a drop-down menu. This will come in useful on more sites than you might imagine (not every site needs a fancy menu), and it will give you the foundation you need to start building more advanced menus.
In this tutorial, I’m going to show you how to create a drop-down menu in your WordPress theme, using CSS to target the HTML that’s output by the WordPress menu function. This is designed for using in a theme you’re coding yourself, and not for a third-party theme, which will already have its own menu. However, if you’re working with a third-party theme whose menu isn’t drop-down and you want to add this, then you’ll need to create a child theme and add your menu code to that.
What You’ll Need
To follow along with this tutorial, you’ll need:
- a development installation of WordPress
- a theme you’re coding yourself, or a child theme of a third-party theme if you want to modify the menu
- a code editor
WordPress’s Built-in Menu Functionality
The first thing you’ll need to understand is how WordPress generates menus. Unlike for static sites, menus aren’t hard-coded into your site. Instead, WordPress uses a PHP function to query the database and fetch navigation menu items, then display them in the correct structure.
Each item in your navigation menu is actually a post in the wp_posts
table in your database—not a normal post, but a special kind of post that’s used just for navigation menu items, with its own metadata including the text to be displayed and the target of the link.
In your theme, open up the header.php file. You should be able to find this line:
wp_nav_menu( array( 'container_class' => 'main-nav', 'theme_location' => 'primary' ) );
Your function may look a little different depending on the parameters, but let’s break down the example above and see what each element does:
-
wp_nav_menu()
is the function that fetches a navigation menu and outputs it. - The parameters are then wrapped in an
array
. -
container_class
is the CSS class that will be given to the container in which the menu is wrapped. In this case, it’smain-nav
. That’s what we’ll be targeting with our CSS later on. -
theme_location => primary
tells WordPress that this is the primary navigation. If I create a menu in the admin screens and check the Primary box, then this menu will be used for this spot in the code.
Sometimes you might want to add a navigation menu elsewhere in your theme, for example in the footer, in which case you don’t want to use theme_location => primary
. You can only use this for one menu. But you may want to use additional parameters, which you can find in the WordPress handbook page on wp_nav_menu()
.
Here’s the checkbox for the primary navigation in the Menus admin screen:
Code Output by the wp_nav_menu()
Function
Before we can add CSS to create the dropdown menu, it helps to be familiar with the code that WordPress generates for menus.
Here’s a typical menu for a small business, shown in the Menus admin screen:
Now here’s the HTML output for that menu:
<div class="main-nav"> <ul id="menu-navbar" class="menu"> <li id="menu-item-610" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item page-item-609 current_page_item menu-item-610"><a href="https://121interviewcoaching.co.uk/">Home</a></li> <li id="menu-item-613" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-613"><a href="https://121interviewcoaching.co.uk/about/">About Me</a></li> <li id="menu-item-615" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-615"><a href="https://121interviewcoaching.co.uk/services/">Services</a> <ul class="sub-menu"> <li id="menu-item-618" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-618"><a href="https://121interviewcoaching.co.uk/services/services-for-individuals/">Preparing for interviews / individuals</a></li> <li id="menu-item-617" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-617"><a href="https://121interviewcoaching.co.uk/services/services-for-groups/">Preparing for interviews / groups</a></li> <li id="menu-item-619" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-619"><a href="https://121interviewcoaching.co.uk/services/conducting-interviews/">Conducting interviews</a></li> </ul> </li> <li id="menu-item-30780" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-30780"><a href="https://121interviewcoaching.co.uk/succeed-at-your-next-job-interview/">My Book</a></li> <li id="menu-item-614" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-614"><a href="https://121interviewcoaching.co.uk/clients-2/">Clients</a></li> <li id="menu-item-616" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-616"><a href="https://121interviewcoaching.co.uk/interview-tips/">Interview Tips</a></li> <li id="menu-item-612" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-612"><a href="https://121interviewcoaching.co.uk/where-i-work/">Areas covered</a></li> <li id="menu-item-611" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-611"><a href="https://121interviewcoaching.co.uk/contact/">Contact & Links</a></li> </ul> </div><!-- #main-nav -->
If you examine that code, you’ll see that it consists of:
- A div with the
main-nav
class, defined in thewp_nav_menu()
function. - Inside that, a
ul
with the IDmenu-navbar
and the classmenu
. These are defaults defined by WordPress. - Inside that, a number of
li
elements, each with the class ofmenu-item menu-item-type-post_type
plus other classes specific to the type of post that the menu item leads to and the state of that menu item at the time. Each one also has a unique ID with a number corresponding to the post ID of the navigation menu item in the database. - Inside one of the
li
elements is anotherul
with its ownli
elements inside—the second level menu items. It’s this that we want to drop down when the user hovers over the top level menu item.
Coding the CSS to Create the Drop-Down Menu
So now we know what’s being output by WordPress, we can determine which elements we want to target with our CSS.
We want to achieve a couple of things:
- When the page is opened, the second-level menu items are hidden.
- When the user hovers over a top-level item, the second-level items below it appear.
Hiding the Second-Level Items by Default
In your theme’s stylesheet, start by hiding the second-level items by default.
Add this:
.main-nav ul ul { display: none; }
This will hide the ul
element inside another ul
element inside the main-nav
element. It won’t hide a top-level ul
element however, as it requires one ul
to be nested inside another ul
inside the menu.
Now if you open the page and try to view the second-level items, it won’t be possible—they’ll be hidden. Let’s fix that.
Making Second-Level Items Appear on Hover
Now we need to ensure that the ul
nested inside the top-level li
will be displayed when the top-level li
is hovered over.
Add this to your stylesheet:
.main-nav ul li:hover > ul { display: block; }
Now when you hover your mouse over the top-level item, the list beneath it will appear. But you’ll find that it won’t display the way you want it. Specifically, it will be pushing down the content below the menu. We want it to appear as if it’s floating on top of the content. To fix that, we need to add some layout styling to our ul ul
element.
Adding Layout Styling to the Second-Level List
Open you stylesheet and find the line with display: none
in it. Edit it that block to add layout styling:
.main-nav ul ul { display: none; position: absolute; top: 3em; left: 0; z-index: 99999; width: 180px; background: #fff; box-shadow: 0px 3px 3px rgba(0,0,0,0.2); }
You also need to give the top level list item relative positioning:
.main-nav li { position: relative; }
Let’s take a look at what that code does:
-
position: absolute
gives the second-level list absolute positioning, taking it out of the flow of the elements in the page. For the higher-level item,position: relative
puts the top level list in the flow of the page and allows for an absolutely positioned element to be placed inside it. -
top: 3em
positions the top of the list relative to the top of the element it’s inside, namely the top level list item. This3em
value reflects the height of the top-level navigation bar. Edit yours if your top-level navigation has a different height. -
left: 0
places the list to the left, relative to the item above it. -
z-index: 99999
defines where the element sits in a three-dimensional model of the page. A high value of99999
ensures that it is displayed on top of everything else. - The remaining code gives the list width and also adds display styling to it, including a shadow to make it look as if it’s on top of the page.
Now let’s take a look at what we see when we hover over the top-level item:
It works! When I hover over the top-level item, the drop-down menu is now displayed.
Drop-Down Menus are Useful for Small Multi-Level Menus
When your site needs a menu with multiple levels, but you don’t need a lot of links outside your top-level menu, a drop-down menu is the simplest way to achieve this. The site I’ve used to demonstrate this only has one item in its menu with other items below it, and there are only three of those. Using a mega menu would be overkill, and a single-level menu wouldn’t allow me to display everything I want.
Being able to add a menu like this to your themes will give you more flexibility with your menus and enhance user experience. And you can do it with just a few lines of CSS.
While you’re here, check out some of our other posts on how WordPress menus and navigation.