Create a Mobile-Only Menu Without a Plugin (WordPress)

December 19, 2025
Create a Mobile-Only Menu Without a Plugin (WordPress)

Many WordPress themes use one navigation menu for all devices. But sometimes you want a separate mobile-only menu — for example, a simplified structure, fewer items, or a bottom navigation bar.

This guide shows how to build a mobile-only menu without any plugin, using a clean theme setup:

  • Register a separate menu location
  • Output it in your theme
  • Show/hide it with CSS (mobile-only)
  • Add optional JavaScript for a toggle (hamburger drawer)

1) Register a Mobile Menu Location

Add this to your theme’s functions.php (or your menu registration file).

add_action( 'after_setup_theme', function() {

  register_nav_menus( array(
    'primary' => 'Primary Menu',
    'mobile'  => 'Mobile Menu',
  ) );

} );

Now you’ll see a new location in Appearance → Menus (or Appearance → Editor for block themes).


2) Assign a Menu to the Mobile Location

Create a new menu like “Mobile Menu” and assign it to the Mobile Menu location.

Keep it simple:

  • Home
  • Blog
  • Categories
  • Contact

3) Output the Mobile Menu in Your Theme

Add this where you want the mobile menu to appear, typically in header.php (or a header template part).

<nav class="mobile-nav" aria-label="Mobile menu">
  <?php
  wp_nav_menu( array(
    'theme_location' => 'mobile',
    'container'      => false,
    'menu_class'     => 'mobile-nav__list',
    'fallback_cb'    => false,
    'depth'          => 2,
  ) );
  ?>
</nav>

Tip: fallback_cb => false prevents WordPress from outputting a random page menu if no menu is assigned.


4) Make It Mobile-Only with CSS

Add CSS to your stylesheet:

.mobile-nav {
  display: none;
}

@media (max-width: 768px) {
  .mobile-nav {
    display: block;
  }

  .site-header .primary-nav {
    display: none;
  }
}

This shows the mobile menu on small screens and hides the desktop nav (adjust selectors to match your theme).


Option A: Simple Mobile Menu (Always Visible)

If you want a basic mobile menu that’s always visible under the header, you’re done.

But many sites prefer a drawer/hamburger menu.


Option B: Mobile Drawer Menu (Hamburger Toggle)

This section adds a toggle button and a sliding panel. It stays lightweight and accessible.


5) Add the Toggle Button

Place this near your mobile nav markup (usually inside the header):

<button class="mobile-nav-toggle"
  type="button"
  aria-controls="mobile-nav-panel"
  aria-expanded="false">
  Menu
</button>

6) Wrap the Menu in a Panel

Update your menu markup to include an ID and panel container:

<div id="mobile-nav-panel" class="mobile-nav-panel" hidden>
  <nav class="mobile-nav" aria-label="Mobile menu">
    <?php
    wp_nav_menu( array(
      'theme_location' => 'mobile',
      'container'      => false,
      'menu_class'     => 'mobile-nav__list',
      'fallback_cb'    => false,
      'depth'          => 2,
    ) );
    ?>
  </nav>
</div>

7) CSS for the Drawer Panel

.mobile-nav-toggle {
  display: none;
}

.mobile-nav-panel {
  position: fixed;
  top: 0;
  right: 0;
  width: min(320px, 85vw);
  height: 100vh;
  padding: 16px;
  background: #fff;
  box-shadow: -8px 0 24px rgba(0,0,0,0.15);
  overflow-y: auto;
  z-index: 9999;
}

@media (max-width: 768px) {
  .mobile-nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
}

8) JavaScript to Toggle the Drawer

Add this as a small script file (or inline). It toggles hidden and updates aria-expanded.

document.addEventListener('DOMContentLoaded', () => {
  const btn = document.querySelector('.mobile-nav-toggle');
  const panel = document.querySelector('#mobile-nav-panel');

  if (!btn || !panel) return;

  const open = () => {
    panel.hidden = false;
    btn.setAttribute('aria-expanded', 'true');
  };

  const close = () => {
    panel.hidden = true;
    btn.setAttribute('aria-expanded', 'false');
  };

  btn.addEventListener('click', () => {
    const expanded = btn.getAttribute('aria-expanded') === 'true';
    expanded ? close() : open();
  });

  document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') close();
  });

  document.addEventListener('click', (e) => {
    if (panel.hidden) return;

    const clickedInside = panel.contains(e.target) || btn.contains(e.target);
    if (!clickedInside) close();
  });
});

9) Enqueue the Mobile Menu Script (Optional)

If you saved the JS to /assets/js/mobile-menu.js:

add_action( 'wp_enqueue_scripts', function() {

  $path = get_stylesheet_directory() . '/assets/js/mobile-menu.js';

  wp_enqueue_script(
    'mobile-menu',
    get_stylesheet_directory_uri() . '/assets/js/mobile-menu.js',
    array(),
    file_exists( $path ) ? filemtime( $path ) : null,
    true
  );

} );

Common Mistakes to Avoid

  • Using one menu for everything and hiding items randomly (hard to maintain)
  • Forgetting fallback_cb => false (unexpected menus appear)
  • Not handling accessibility (aria-expanded, Escape key)
  • Hiding menus only with JS (users without JS should still navigate)

Conclusion

A mobile-only menu is easy to build in WordPress without plugins: register a separate menu location, output it in your theme, and control visibility with CSS. If you need a modern drawer menu, add a small toggle script and keep it accessible.

Key takeaway:
Use a dedicated menu location for mobile — it’s cleaner, easier to manage, and scales better than conditional hacks.

Avatar

Written by

satoshi

I’ve been building and customizing WordPress themes for over 10 years. In my free time, you’ll probably find me enjoying a good football match.