Skip to content

WordPress Menu

Register menu locations


Register each menu with a location (like a unique slug) and a description. The description will be shown on Wp-Admin > Appearance > Menus > Manage Locations.

    // 'location'  => 'description',
    'main_menu' => 'Main menu',
    'sub_menu1' => 'Sub menu 1 (top left)',
    'sub_menu2' => 'Sub menu 2 (top right)',
    'sub_menu3' => 'Sub menu 3 (bottom left)',
    'sub_menu4' => 'Sub menu 4 (bottom right)',

Display the menu in a theme

WordPress documentation: wp_nav_menu()

menu can be the menu ID, slug, name, or object.

Display menu using the theme_location from the above setup. That way the theme will not rely on a specific name of a menu existing, but it does rely on a menu being set for that location.

menu_class is the css class that will be added to the ul of the menu output. It can be more than one class, e.g. 'sub-menu position-2'

Setting container to false will remove the container element (default is a div) that normally contains the ul.

      'theme_location'  => 'main_menu',
      'menu_class'      => 'main-menu',
      'items_wrap'      => '<ul class="%2$s">%3$s</ul>', // remove the id on the ul element
      'container'       => false

Display a menu using a name (relies on this name being added through the WordPress admin).

      'menu' => 'Menu 1', 

Assuming we use the menu class .main-menu as per above, we can style the menu like so. This assumes a custom breakpoint has been added in Tailwind called menu. See Tailwind Breakpoints

# Main Menu 

.main-menu {
  @apply hidden menu:flex space-x-12;

.main-menu > li > a {
  @apply text-base md:text-xl transition-opacity duration-300 hover:opacity-70;

  .dark-header & {
    @apply text-white;

If the menu has a second level sub-menu use the following css. This assumes a custom breakpoint has been added in Tailwind called menu. See Tailwind Breakpoints

# Sub-menu 

/* Desktop menu */
@media screen(menu) {
  .sub-menu {
    @apply absolute hidden opacity-0 w-max;

  .main-menu li:hover > .sub-menu,
  .main-menu li:focus-within > .sub-menu {
    @apply visible block opacity-100;

  .sub-menu > li > a {
    @apply block px-2 font-semibold leading-10 tracking-wider uppercase transition-opacity duration-300 md:text-sm md:leading-10;

/* Mobile menu overlay */
.mobile-menu {
  .sub-menu {
    @apply pl-5;

  a {
    @apply block py-1 leading-10 tracking-wider;

  .current_page_item {
    @apply underline underline-offset-8;


Credit: Based on

Overlay modal menu

Micromodal.js is a lightweight, configurable and a11y-enabled modal library written in pure JavaScript.

Save micromodal.min.js to /js folder.

Enqueue in functions.php.

wp_enqueue_script( 'projectX-micromodal', get_stylesheet_directory_uri() . '/js/micromodal.min.js' );

Add html to footer.php. The micromodal code also changes the aria-expanded attribute to the current state. Note the svg in the close button has the class pointer-events-none to endure the entire button is clickable.

<!-- Modal Mobile Menu -->
<div id="menu-modal" aria-hidden="true">
    class="h-screen p-5 overflow-auto bg-white modal-overlay" 

      <header class="flex justify-between">
          href="<?php echo esc_url( home_url( '/' ) ); ?>" 
          title="Return to the homepage"
        <button aria-label="Close modal" data-micromodal-close class="p-4">
          <svg xmlns="" height="48" viewBox="0 -960 960 960" width="48"><path d="M249-193.434 193.434-249l231-231-231-231L249-766.566l231 231 231-231L766.566-711l-231 231 231 231L711-193.434l-231-231-231 231Z" class="fill-white pointer-events-none"/></svg>

      <div id="menu-modal-content">
        Menu items


  disableScroll: true, 
  awaitCloseAnimation: true, 
  onShow: modal => {
    document.getElementById("hamburger").setAttribute('aria-expanded', true);
  onClose: modal => {
    document.getElementById("hamburger").setAttribute('aria-expanded', false);

Add the attribute to the hamburger button. menu-modal below must match the id of the main <div> above.

<button data-micromodal-trigger="menu-modal"></button>

Full hamburger html example. This assumes the custom Tailwind breakpoint menu has been added to the Tailwind config. See Tailwind Breakpoints

<nav class="main-navigation" aria-labelledby="hamburger">
    class="leading-none rounded hamburger focus:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-4 menu:hidden"
    aria-label="navigation menu"
    <svg xmlns="" width="41" height="30" class="menu-desktop"><g fill="#ffffff"><path d="M7 0h34v6H7z"/><path d="M0 12h41v6H0z"/><path d="M12 24h29v6H12z"/></g></svg>


Add the css for the modal.

# Menu Modal
--------------------------------------------------------------*/ {
  z-index: 99999; /* This is the minimum to be above admin bar */  
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;

@keyframes mmfadeIn {
  from { opacity: 0; transform: scale(0.95); }
    to { opacity: 1; transform: scale(1); }

@keyframes mmfadeOut {
  from { opacity: 1; transform: scale(1); }
    to { opacity: 0; transform: scale(0.95); }

#menu-modal {
  display: none;
} {
  display: block;

#menu-modal[aria-hidden="false"] .modal-overlay {
  animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);

#menu-modal[aria-hidden="true"] .modal-overlay {
  animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);