Creating nested menus

You can add nested navigation menus to your online store using simplified Liquid syntax. Shopify's nested navigation feature includes the following:

  • Nested menu UI - Merchants can create nested menus up to 3 levels deep from a single page by using the menu editing interface
  • Backward-compatibility layer - Although menus created with the nested menu UI are stored differently than non-nested menus, they work the same way with current Liquid markup
  • Simplified Liquid markup - You can use simplified Liquid markup, including help with styling, to render nested menus.

Backward compatibility with legacy Liquid code

Menus created with the nested menu UI will work with your existing Liquid code. You do not need to make any updates. The number of supported nested menu levels depends on the theme.

How legacy code works with the nested menu UI

When using legacy Liquid markup with the nested menu UI, you can render nested menus by looking up child menus using link titles passed through the handleize filter. Although you must manually set up menus that adhere to this naming convention to configure nesting, the nested menu UI handles this transparently in the background.

For example, given the following menu structure:

Main Menu
  └ Home
  └ About Us
    └ Locations
      └ Montreal
      └ Ottawa

the following Liquid code:

{% assign about_us_link = linklists.main-menu.links.last %}
{% assign child_list_handle = about_us_link.title | handleize %}
child_list_handle: {{ child_list_handle }}
{% assign child_list = linklists[child_list_handle] %}
{{ child_list.links.first.title }}

would produce the following output:

child_list_handle: about-us
Locations

Nested menu Liquid syntax

You can use simplified Liquid syntax for nested menus:

Instead of relying on {{ child_link.title | handleize }}, nested menu items can be obtained directly from their parent link. This greatly simplifies the markup required to render a nested menu.

<ul>
{% for link in linklists.main-menu.links %}
  <li>
    <a href="{{ link.url }}">{{ link.title | escape }}</a>
    {% if link.links != blank %}
      <ul class="dropdown">
        {% for child_link in link.links %}
          <!-- ... --->

When rendering a menu, it's often helpful to know how many levels of nesting it contains. For example, given the following main menu structure:

Main Menu
  └ Home
  └ About Us
    └ Locations
      └ Montreal
      └ Ottawa

The following Liquid code:

  {% assign menu = linklists.main-menu %}
  <pre>
  {{ menu.title }}: {{ menu.levels }}
  {% for link in menu.links %}
    {{ link.title }}: {{ link.levels }}
    {% for sub_link in link.links %}
      {{ sub_link.title }}: {{ sub_link.levels }}
      {% for sub_sub_link in sub_link.links %}
        {{ sub_sub_link.title }}: {{ sub_sub_link.levels }}
      {% endfor %}
    {% endfor %}
  {% endfor %}
  </pre>

produces the following output (edited for space):

Main Menu: 3
  Home: 0
  About Us: 2
    Locations: 1
      Montreal: 0
      Ottawa: 0

link.active is often used to style menu items that point to the current page, but there is no easy way of finding out whether any of its nested items point to it as well. link.child_active serves that purpose.

For example, given the following main menu structure:

Main Menu
  └ Home
  └ About Us
    └ In the news
    └ Locations
      └ Montreal
      └ Ottawa

the following Liquid code:

  {% assign menu = linklists.main-menu %}
  <pre>
  {{ menu.title }}
  {% for link in menu.links %}
    {{ link.title }}: active: {{ link.active }}, child_active: {{ link.child_active }}
    {% for sub_link in link.links %}
      {{ sub_link.title }}: active: {{ sub_link.active }}, child_active: {{ sub_link.child_active }}
      {% for sub_sub_link in sub_link.links %}
        {{ sub_sub_link.title }}: active: {{ sub_sub_link.active }}, child_active: {{ sub_sub_link.child_active }}
      {% endfor %}
    {% endfor %}
  {% endfor %}
  </pre>

produces the following output for the page for Montreal (edited for space):

Main Menu
  Home: active: false, child_active: false
  About Us: active: false, child_active: true
    In the news: active: false, child_active: false
    Locations: active: false, child_active: true
      Montreal: active: true, child_active: false
      Ottawa: active: false, child_active: false

FAQ

  • Will there be an API for menus? Yes, but we can't announce a timeline just yet.
  • Why does it allow only 3 levels of nesting? How do I handle more complex cases? Based on our analysis of themes now in use, we concluded that 3 levels of nesting should cover the vast majority of use cases. More complex scenarios can be handled using the link_list setting type.

Ready to start selling with Shopify?

Try it free