Navigation Liquid Objects and Linklists
Master the Liquid objects for navigation, including linklists, links, and how to detect active states for building dynamic menus.
Shopify exposes menu data through Liquid objects. Understanding these objects is essential for building navigation components that reflect the menus merchants create in the admin.
The linklists Object
The linklists object contains all menus defined in the store. Access a specific menu by its handle:
{{ linklists['main-menu'] }}{{ linklists['footer'] }}{{ linklists.main-menu }}Both bracket notation and dot notation work, but bracket notation is safer for handles with hyphens.
Linklist Properties
Each linklist (menu) has these properties:
{%- assign menu = linklists['main-menu'] -%}
{{ menu.title }} {# "Main menu" #}{{ menu.handle }} {# "main-menu" #}{{ menu.levels }} {# Number of nesting levels (1-3) #}{{ menu.links }} {# Array of link objects #}{{ menu.links.size }} {# Number of top-level links #}The links Array
Each linklist contains a links array with link objects:
{%- for link in linklists['main-menu'].links -%} {{ link.title }}{%- endfor -%}Link Properties
Each link object provides:
| Property | Description | Example |
|---|---|---|
title | Display text | ”About Us” |
url | Link destination | ”/pages/about” |
handle | URL-safe identifier | ”about-us” |
active | True if current page | true or false |
child_active | True if a child is active | true or false |
current | True if exact URL match | true or false |
links | Array of child links | [...] |
levels | Nesting depth below this link | 0, 1, or 2 |
type | Link type | ”collection_link”, “page_link”, etc. |
object | The linked object | Collection, product, page, etc. |
Basic Navigation Loop
Here’s a simple navigation rendering:
<nav> <ul class="nav-list"> {%- for link in linklists['main-menu'].links -%} <li class="nav-item"> <a href="{{ link.url }}" class="nav-link"> {{ link.title }} </a> </li> {%- endfor -%} </ul></nav>Active States
Use active and child_active to highlight the current section:
{%- for link in linklists['main-menu'].links -%} <li class="nav-item"> <a href="{{ link.url }}" class="nav-link {% if link.active %}is-active{% endif %}" {% if link.active %}aria-current="page"{% endif %} > {{ link.title }} </a> </li>{%- endfor -%}Understanding Active States
| Property | When it’s true |
|---|---|
active | The current page matches this link’s URL |
child_active | A descendant link matches the current page |
current | Exact URL match (stricter than active) |
Example scenarios on /collections/shirts:
| Link URL | active | child_active |
|---|---|---|
/collections/shirts | true | false |
/collections | true | false |
/ (Home) | false | false |
| ”Shop” (parent of Shirts) | false | true |
Nested Navigation
Handle child links for dropdown menus:
<nav> <ul class="nav-list"> {%- for link in linklists['main-menu'].links -%} <li class="nav-item {% if link.links.size > 0 %}has-dropdown{% endif %}"> <a href="{{ link.url }}" class="nav-link {% if link.active or link.child_active %}is-active{% endif %}" > {{ link.title }} {%- if link.links.size > 0 -%} <span class="dropdown-icon">▼</span> {%- endif -%} </a>
{%- if link.links.size > 0 -%} <ul class="dropdown-menu"> {%- for child_link in link.links -%} <li class="dropdown-item"> <a href="{{ child_link.url }}" class="dropdown-link {% if child_link.active %}is-active{% endif %}" > {{ child_link.title }} </a> </li> {%- endfor -%} </ul> {%- endif -%} </li> {%- endfor -%} </ul></nav>Three-Level Nesting
For deeply nested menus:
{%- for link in linklists['main-menu'].links -%} <div class="nav-item"> <a href="{{ link.url }}">{{ link.title }}</a>
{%- if link.links.size > 0 -%} <div class="submenu"> {%- for child in link.links -%} <div class="submenu-item"> <a href="{{ child.url }}">{{ child.title }}</a>
{%- if child.links.size > 0 -%} <div class="submenu-level-2"> {%- for grandchild in child.links -%} <a href="{{ grandchild.url }}">{{ grandchild.title }}</a> {%- endfor -%} </div> {%- endif -%} </div> {%- endfor -%} </div> {%- endif -%} </div>{%- endfor -%}Link Types
The link.type property tells you what kind of link it is:
{%- case link.type -%} {%- when 'collection_link' -%} {# Link to a collection #} {%- when 'product_link' -%} {# Link to a product #} {%- when 'page_link' -%} {# Link to a page #} {%- when 'blog_link' -%} {# Link to a blog #} {%- when 'article_link' -%} {# Link to a blog article #} {%- when 'policy_link' -%} {# Link to a policy page #} {%- when 'http_link' -%} {# External or custom URL #} {%- when 'frontpage_link' -%} {# Link to homepage #} {%- when 'catalog_link' -%} {# Link to /collections/all #}{%- endcase -%}Accessing the Linked Object
For collection and product links, access the underlying object:
{%- for link in linklists['main-menu'].links -%} {%- if link.type == 'collection_link' -%} {# Access the collection object #} <a href="{{ link.url }}"> {{ link.title }} <span>({{ link.object.products_count }} products)</span> </a>
{# Show collection image #} {%- if link.object.image -%} <img src="{{ link.object.image | image_url: width: 200 }}" alt=""> {%- endif -%} {%- else -%} <a href="{{ link.url }}">{{ link.title }}</a> {%- endif -%}{%- endfor -%}This is powerful for megamenus that show collection images or product counts.
Using Theme Settings for Menu Selection
Let merchants choose which menu to use:
{ "type": "link_list", "id": "menu", "label": "Menu", "default": "main-menu"}{%- assign menu = linklists[section.settings.menu] -%}
{%- for link in menu.links -%} <a href="{{ link.url }}">{{ link.title }}</a>{%- endfor -%}Checking if Menu Exists
Guard against missing menus:
{%- assign menu = linklists[section.settings.menu] -%}
{%- if menu.links.size > 0 -%} <nav> {%- for link in menu.links -%} <a href="{{ link.url }}">{{ link.title }}</a> {%- endfor -%} </nav>{%- else -%} {# Fallback or empty state #}{%- endif -%}External Links
Detect and handle external links:
{%- for link in menu.links -%} {%- assign is_external = false -%} {%- if link.url contains 'http' and link.url contains '://' -%} {%- unless link.url contains shop.domain -%} {%- assign is_external = true -%} {%- endunless -%} {%- endif -%}
<a href="{{ link.url }}" {% if is_external %}target="_blank" rel="noopener noreferrer"{% endif %} > {{ link.title }} {%- if is_external %} <span class="external-icon">↗</span>{%- endif -%} </a>{%- endfor -%}Complete Navigation Snippet
Here’s a reusable navigation snippet:
{# snippets/navigation.liquid #}{# Usage: {% render 'navigation', menu: linklists['main-menu'], class: 'header-nav' %} #}
{%- if menu.links.size > 0 -%} <nav class="{{ class }}" aria-label="{{ menu.title }}"> <ul class="{{ class }}__list"> {%- for link in menu.links -%} {%- liquid assign has_children = false if link.links.size > 0 assign has_children = true endif
assign is_active = false if link.active or link.child_active assign is_active = true endif -%}
<li class="{{ class }}__item {% if has_children %}has-dropdown{% endif %}"> <a href="{{ link.url }}" class="{{ class }}__link {% if is_active %}is-active{% endif %}" {% if link.active %}aria-current="page"{% endif %} {% if has_children %}aria-expanded="false" aria-haspopup="true"{% endif %} > {{ link.title }} </a>
{%- if has_children -%} <ul class="{{ class }}__dropdown"> {%- for child in link.links -%} <li class="{{ class }}__dropdown-item"> <a href="{{ child.url }}" class="{{ class }}__dropdown-link {% if child.active %}is-active{% endif %}" {% if child.active %}aria-current="page"{% endif %} > {{ child.title }} </a> </li> {%- endfor -%} </ul> {%- endif -%} </li> {%- endfor -%} </ul> </nav>{%- endif -%}Practice Exercise
Create a footer navigation that:
- Renders menu columns from nested links
- Shows parent titles as column headings
- Lists child links below
<footer class="footer"> <div class="footer-nav"> {%- for column in linklists['footer'].links -%} <div class="footer-column"> <h4 class="footer-column__heading">{{ column.title }}</h4>
{%- if column.links.size > 0 -%} <ul class="footer-column__list"> {%- for link in column.links -%} <li> <a href="{{ link.url }}">{{ link.title }}</a> </li> {%- endfor -%} </ul> {%- else -%} {# If no children, link the heading #} <a href="{{ column.url }}">View {{ column.title }}</a> {%- endif -%} </div> {%- endfor -%} </div></footer>Key Takeaways
linklists['handle']accesses menus by handlelink.linkscontains child links for nestinglink.activeis true when on the linked pagelink.child_activeis true when a descendant is activelink.typeidentifies the link type (collection, page, etc.)link.objectgives access to the linked resource- Use settings to let merchants choose menus
- Always check if menu exists before rendering
What’s Next?
Now that you understand navigation Liquid objects, the next lesson covers Building the Header Section where we’ll put everything together into a complete header component.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...