Mobile Nav Menus

One of the most common features of any modern website is a dropdown navigation button, commonly known as a hamburger menu. These dropdown buttons are typically JavaScript-based and therefore are not AMP compatible by default, as the AMP framework limits usage of JavaScript to components such as ‘amp-script’ and ‘amp-bind‘. 

Luckily, many theme developers have taken this into account in their theme, ensuring full functionality when using AMP. We’ve compiled a list of confirmed AMP-compatible themes for you to test out. 

For themes that are not AMP-compatible, this document explains why your navigation menu won’t work in AMP and the steps you can take to implement a solution. 

Why won’t the navigation menu work? #

Navigation menus are typically JavaScript-based. Because JavaScript is the number one cause of poor website performance, AMP sets limits on the use of custom JavaScript. For that reason, navigation menus or other JavaScript-based features won’t work in AMP by default. 

Why can’t the plugin fix it? #

All themes are built differently, using different classes, markup, and styles. It’s not possible for any one plugin or solution to address all AMP incompatibilities. We’re always happy to help where possible, so if you’re having trouble with the options below, reach out to us in the support forums

Note that while we may be able to point you in the right direction, it’s ultimately up to theme developers or end users to make their own themes or sites AMP-compatible.  

What can I do to make my navigation menu work? #

There are a few options that you can choose. Click on any of the below for more information. 

  1. Contact your theme developer
  2. Use the plugin in reader mode
  3. Switch to an AMP-compatible alternative
  4. Use the AMP Compatibility plugin
  5. Make programmatic changes using ‘nav_menu_toggle’
  6. Make programmatic changes using ‘amp-bind’
  7. Use the ‘amp-sidebar’ component
  8. Reach out in the support forums

Also check this video, produced by our guest contributor:

Contact your theme developer #

Contact the developer of your theme and suggest that they make their theme AMP-compatible by ensuring that JavaScript-based features like navigation menus work in AMP. 

If contacting the developer let them know of this resource, which can be used as guidance for toggling hamburger menus. 

Use AMP in Reader Mode #

If you’re looking to test out AMP and compare the performance of your AMP site versus your non-AMP URLs without impacting your non-AMP URLs, the AMP plugin’s Reader Mode is a good option.  With reader mode active, you can choose a separate AMP-compatible theme that will become active for your AMP URLs only so that your navigation can continue to work as is in your non-AMP theme. 

If you’ve installed a compatible theme and you don’t see it available for selection in reader mode themes, you can add an AMP: true flag to the theme’s ‘functions.php’ file. You’ll find more information on this page

Switch to an alternative AMP-compatible theme #

There are an ever increasing number of AMP- compatible themes that work with both AMP and non-AMP pages. In addition to explicitly AMP compatible themes, we also have a collection of compatibility extensions that ensure functionality in AMP URLs. 

You can test out any of the AMP-compatible themes in reader mode if you wish so you can see how it will work for your site. If you’ve installed a compatible theme and you don’t see it available for selection in reader mode themes, you can add an AMP: true flag to the themes ‘functions.php’ file. You’ll find more information on this page

Use an AMP Compatibility plugin #

Using a compatibility plugin can ensure that your navigation menu works on both AMP and non-AMP URLs. In order to use the AMP Compatibility plugin, you’ll need an understanding of how to use your browser’s developer tools to determine your navigation menu’s markup, specifically the IDs associated with the hamburger navigation button. 

You’ll find full instructions on how to use the AMP Compatibility plugin  in the plugin’s GitHub repository

Make programmatic changes using nav_menu_toggle #

You can also use a  theme support flag called nav_menu_toggle for navigation menu compatibility. Similar to the compatibility plugin option above, this option requires that you have an understanding of how to use your browser’s developer tools to determine your navigation menu’s markup.

An example of a working nav_menu_toggle flag can be viewed below, and you can add this to your theme’s ‘functions.php’ file, child theme, or a custom plugin to ensure this code doesn’t get overwritten by theme updates:

add_theme_support(
	'amp',
	array(
		'nav_menu_toggle'   => array(
			'nav_container_id'           => 'site-navigation',
			'nav_container_toggle_class' => 'toggled-on',
			'menu_button_id'             => 'site-navigation-toggle',
			'menu_button_toggle_class'   => 'toggled-on',
		),
	)
);Code language: PHP (php)

If no element ID is available for ‘nav_container_id’, then you may instead use ‘nav_container_xpath’. Similarly, if there is no element ID available for ‘menu_button_id’, then you may use ‘menu_button_xpath’.

Make programmatic changes using ‘amp-bind’ #

The ‘amp-bind‘ component can be used as an AMP-compatible way to toggle CSS classes associated with your navigation menu. 

To help you understand how these changes function and how ‘amp-bind’ can be used, take a look at the below jQuery-based navigation menu implementation:

$( '#menu-toggle' ).on( 'click', function() {
    var button = $( this ), nav = $( '#site-header-menu' );
    button.toggleClass( 'toggled-on' );
    nav.toggleClass( 'toggled-on' );
    button.attr( 'aria-expanded', button.hasClass( 'toggled-on' ) ? 'true' : 'false' );
    nav.attr( 'aria-expanded', button.hasClass( 'toggled-on' ) ? 'true' : 'false' );
} );Code language: JavaScript (javascript)

This approach is not AMP-compatible and it  will not work on AMP URLs by default. You’ll notice this incompatibility when using the AMP plugin’s developer tools, as the plugin will strip this code out of AMP URLs to maintain AMP compatibility. 

The ‘amp-bind‘ component lets you write a subset of JavaScript in which you define some state on the page (‘amp-state’), manipulate the state (‘AMP.setState()’), and then react to changes to the state (via the bracketed binding attributes).

Below is an example of defining a ‘navMenuExpanded’ state property with a default value of ‘false’. This includes a button that has an AMP ‘on’ attribute that takes calls for ‘AMP.setState()’ to toggle the ‘navMenuExpanded’ state when the user taps on it. Then both the button and the nav have their class and ‘aria-expanded’ attributes bound to changes to the ‘navMenuExpanded’ state so that they get updated when it changes:

<amp-state id="navMenuExpanded">
        <script type="application/json">false</script>
</amp-state>

<!-- 2. Mutate the state -->
<button
        class="menu-toggle"
        on="tap:AMP.setState( { navMenuExpanded: ! navMenuExpanded } )"
        [class]="'menu-toggle' + ( navMenuExpanded ? ' toggled-on' : '' )"
        aria-expanded="false"
        [aria-expanded]="navMenuExpanded ? 'true' : 'false'"
>
        <?php _e( 'Menu', 'example' ); ?>
</button>

<!-- 3. React to state changes -->
<nav
        class="site-header-menu"
        [class]="'site-header-menu' + ( navMenuExpanded ? ' toggled-on' : '' )"
        aria-expanded="false"
        [aria-expanded]="navMenuExpanded ? 'true' : 'false'"
>
        <?php wp_nav_menu( /* ... */ ); ?>
</nav>Code language: HTML, XML (xml)

If you intend to serve this markup in non-AMP responses as well, you would want to wrap the AMP-specific elements and attributes in ‘if ( example_is_amp() )’ conditionals.

Use the AMP-sidebar component #

You could implement your own sidebar using the amp-sidebar component, which allows you to create a working navigation menu independent of your existing WordPress menu. You can then style this navigation menu any way you choose. 

Below you’ll see an example piece of ‘amp-sidebar’ markup that you can add into a custom HTML block to a post on your website. You can then visit the AMP version of that page to test how it works; this is a demo snippet from the ‘amp-sidebar’ playground. Note that the AMP plugin will automatically request the ‘amp-sidebar’ component script once there is a valid ‘amp-sidebar’ added to your site. This ensures that you don’t need to enqueue or add the component script to the ‘head’ of your site. 

     <div>
        <amp-sidebar id="sidebar-left" class="sample-sidebar" layout="nodisplay" side="left">
          <h3>Sidebar</h3>
          <button on="tap:sidebar-left.close">Close sidebar</button>
          <nav toolbar="(min-width: 784px)" toolbar-target="target-element-left">
            <ul>
              <li>Nav item 1</li>
              <li>Nav item 2</li>
            </ul>
          </nav>
          <ul>
            <li>Nav item 3</li>
            <li>Nav item 4</li>
          </ul>
        </amp-sidebar>
        <button on="tap:sidebar-left.toggle">Toggle sidebar</button>
        <div id="target-element-left">
        </div>
      </div>Code language: HTML, XML (xml)

If you’re looking to associate your existing WordPress navigation menu into your amp-sidebar, you’ll need to be familiar with wp_nav_menu.

Reach out in the support forums #

While we’re not able to make programmatic changes to your theme directly, our savvy and friendly support representatives may be able to point you in the right direction or provide assistance when it comes to basic navigation menu fixes. 

If the theme you are using is a popular theme with a straightforward navigation menu, we may propose that you submit your theme for review by our team. It may be possible for us to provide you with a solution which we can list on our mini plugins and extensions page.