Nested navigations are a popular solution for effectively organizing collections, products, and pages. A link list is a simple collection of links, and these items can be created to point to collection, page, or product within Shopify, or to a URL outside of the store’s domain. In this tutorial, we will cover how to use link lists in a Shopify theme to create a nested navigation using an unordered list. In this article you will learn:
Link lists are used for a variety of different use cases. In this tutorial, we will cover how to use link lists in a Shopify theme to create a nested navigation using an unordered list. By using link lists and Liquid, we’ll have full control over the menu from within the admin, giving flexibility to the merchant running the store.
Before we start let’s set up a development store that we can work with. That way we can test, break, and fix things as we build, and once we’re happy with our code we can move it into production.
In 2017, Shopify added the ability to create a nested navigation menu, up to three levels deep from a single page, by using a new menu editing interface. Previously, menus were created using multiple menus, and the handle for each menu to tie it to its parent menu link.
At the time of writing this article, all newly created stores have the new nested menus user interface, where you can easily drag, drop, and nest menu items, meaning you no longer have to link handles to menu names.
While it’s common to include the navigation in a layout file, the default one being theme.liquid, you can test out the nested navigation concept in any template.
In order to output the menu in a theme file, we’ll need to know the handle of the menu. Handles are unique identifiers within Shopify for products, collections, link lists, and pages.
Let’s begin by outputting all the items from the Main Menu link list. We can use a simple for loop we’ve used many times before to output the link list items in turn:
<ul>
{% for link in linklists.main-menu.links %}
<li><a href= "{{ link.url }}">{{ link.title }}</a></li>
{% endfor %}
</ul>
The key thing to pay attention to here, is the for-loop that’s been included around each <li>.
{% for link in linklists.main-menu.links %}
We are using the variable link to hold the data relating to each item in the link list, as we loop over all the items. This keyword link could be anything, it’s just a variable for the for-loop to output data for the menu. In order to access link data, we need to access all the links in the link list with a handle of main-menu, hence linklists.main-menu.links.
Remember, the default Main Menu that exists in a Shopify store has the handle of main-menu, which is why it’s being used above. If our menu had a handle of social-media, the syntax would be refactored as:
{% for link in linklists.social-media.links %}
Each link item has properties which include:
In the example above, {{ link.url }} will output the url we entered or generated in the Shopify Admin, and {{ link.title }} will output the link text specific to that url.
Now that we have the basic Liquid structure in place for a single level menu, we need to consider how to create a sub-menu for our top level items. Firstly, we need to head back to the Shopify Admin and create our first sub-menu.
It might not be 100 percent clear initially, but every link in a link list, in addition to the menu itself, has a unique handle that we have access to in Liquid.
Let’s have a look at an example. If our main-menu has three levels of links as follows:
What’s great about using nested menus in Shopify is that nested menu items can be obtained directly from their parent link using Liquid. This greatly simplifies the markup required to render a nested menu — meaning you don’t need to know the handle of the parent to render its children.
Here’s an example of how we can use these related handles to output a three level deep nested menu:
<ul class="parent">
{% for link in linklists.main-menu.links %}
<li><a href="{{ link.url }}">{{ link.title }}</a>
{% if link.links != blank %}
<ul class="child">
{% for child_link in link.links %}
<li><a href= "{{ child_link.url }}">{{ child_link.title }}</a>
{% if child_link.links != blank %}
<ul class="grandchild">
{% for grandchild_link in child_link.links %}
<li><a href= "{{ grandchild_link.url }}">{{ grandchild_link.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
You’ll notice that we’re now introducing an if statement in our refactored example, directly after we output the first level of our main menu:
{% if link.links != blank %}
This if statement checks to see if a child-link for the current link item in our loop exists. If it does exist, the template moves forward and loops over all the items in the sub menu.
Additionally, in this example we handle child_link sub-menu and a grandchild_link sub-menu the same way, by checking with an if statement to see if there’s a child-link for the current link item, and if it does exist, the template loops through and outputs the sub-menu.
In the example above, child_link is just a for loop variable we use to represent the current item in the loop; it could easily be replaced with sub_link, and grandchild_link with sub_sub_link. We’ve used child and grandchild in this case to illustrate the hierarchy of the nested navigation a bit more clearly.
I think it’s important to mention one extra link property that will be very useful when creating menus — link.active and link.child_active. These are both boolean properties (true/false) that allow you to easily tell if the current page is active, as well as if it’s nested items are active. The syntax is as follows:
{% if link.active %} class="active {% if link.child_active %}child-active{% endif %}"{% endif %}
In this example, we’ll add a CSS class of active if the current page URL is the same as the list item, and a class of active-child if the current page is also part of the active nested item. Here’s the full code example for completeness:
<ul class="parent">
{% for link in linklists.main-menu.links %}
<li {% if link.active %}class="active {% if link.child_active %}child-active{% endif %}"{% endif %}><a href="{{ link.url }}">{{ link.title }}</a>
{% if link.links != blank %}
<ul class="child">
{% for child_link in link.links %}
<li {% if child_link.active %}class="active {% if child_link.child_active %}child-active{% endif %}"{% endif %}><a href= "{{ child_link.url }}">{{ child_link.title }}</a>
{% if child_link.links != blank %}
<ul class="grandchild">
{% for grandchild_link in child_link.links %}
<li {% if grandchild_link.active %}class="active {% if grandchild_link.child_active %}child-active{% endif %}"{% endif %}><a href= "{{ grandchild_link.url }}">{{ grandchild_link.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
Link lists are a very powerful element of the Shopify platform. Having the ability to create an array of list items that can be changed in the admin gives you lots of flexibility. We’ve seen theme developers use them far beyond menu structures. However, knowing how to create nested navigation that can then be styled with CSS is a great tool to have at your disposal.
Work with our skilled Shopify developers to accelerate your project and boost its performance.
3rd Floor, Aval Complex, University Road, above Balaji Super Market, Panchayat Nagar Chowk, Indira Circle, Rajkot, Gujarat 360005.
Abbotsford, BC
15th B Street 103, al Otaiba Dubai DU 00000, United Arab Emirates
3rd Floor, Aval Complex, University Road, above Balaji Super Market, Panchayat Nagar Chowk, Indira Circle, Rajkot, Gujarat 360005.
Abbotsford, BC.
15th B Street 103, al Otaiba Dubai DU 00000, United Arab Emirates.
Copyright © 2026 Niotechone Software Solution Pvt. Ltd. All Rights Reserved.