Building navigation

hey, I think you need to integrate information from this same page: this is a good issues page:


Instead of hard-coding navigation links to pages, you can use Liquid logic to retrieve a list of pages. There are two primary ways of retrieving pages:

  • Retrieving pages listed in a YAML data source. The YAML is either stored in a separate data file (in the _data folder) or in the page’s front matter (and accessed through site variables). Note that the pages don’t need to be YAML only (.yaml or .yml). You could also use any files ending in .json or .csv. However, the markup-less structure in YAML makes it more readable, since the spacing drives the syntax.
  • Retrieving pages by looping through the page front matter. You can use for loops to look through the site.pages or site.collections spaces to retrieve pages or documents that have particular properties in their front matter. For loops create longer build times, but sometimes this approach can be more efficient.

Note that the techniques described here for using Liquid and YAML will be brief, since you can view the full documentation for using these formats on other sites. The focus here is on building page-based navigation for a Jekyll site.

The examples that folow start with a basic navigation scenario and add more sophisticated elements to demonstrate different ways of returning the pages.

In almost every scenario, you’ll see 3 elements:

  • YAML
  • Liquid
  • Result

Scenario 1: Basic List

You want to return a basic list of pages.

YAML You have a data file named samplelist.yml in _data.

podcast_list_title: Favorite Podcasts

- title: This Week in Tech

- title: Radio Lab

- title: Night Vale


<h2>Favorite Podcasts</h2>
{% for item in %}
<li><a href="{{item.url}}" alt="{{item.title}}">{{item.title}}</a></li>
{% endfor %}


When you use a for loop, you choose the variable of what to call the things you’re looping through. The variable you choose (in this case, item) becomes how you access the properties of each thing in the list. Dot notation is used to get each property of each thing (for example, item.url).

The YAML content has two main types of formats that are relevant here:

  • mapping
  • list

podcast_list_title: My Favorite Podcasts is a mapping. You access the file with

podcasts: is a list. The list begins each item with a hyphen. Unlike with mappings, you can’t access list properties directly like you can with a mapping. If you want to access a specific item in the list, you must identify get the position in the list you want, following typical array notation. For example,[0] would access the first item in the list.

With lists, you usually don’t access positions using the [0] syntax. Instead, you use for loops to cycle through the list of items and do something with each item. With navigation menus, you’re usually insert each list item into li tags based on the navigation structure you’re building in your HTML theme.

Each - indicates another item in the list. Here we list just two properties: title and url. You can list as many properties as you want for each item. The order of properties at each position in the list doesn’t matter.

Sorting the list

Suppose you wanted to sort the list by the title. To do this, convert the reference to the list to a variable, and then apply Liquid’s sort filter to the variable:


{% assign podcasts = | sort: 'title'  %}
{% for item in podcasts %}
{% endfor %}


Night Vale Radio Lab This Week in Tech

The sort property in the Liquid filter applies to the title. title is an actual property in the list. If title weren’t a property, this sorting method wouldn’t work.

See Liquid array filter for more filter options. Note that you can’t simply use {% for item in sort: ‘title’ %} . You have to convert site.dat.samplelist.podcasts to a variable first using either assign or capture tags.

Scenario 2: Two-level navigation list

Now let’s say you want a more robust list that incorporates heading titles and subitems. To do this, add an additional level to each list item to store this information:


  - title: Group 1
      - page: Thing 1
        url: /thing1.html
      - page: Thing 2
        url: /thing2.html
      - page: Thing 3
        url: /thing3.html
  - title: Group 2
      - page: Piece 1
        url: /piece1.html
      - page: Piece 2
        url: /piece2.html
      - page: Piece 3
        url: /piece3.html
  - title: Group 3
      - page: Widget 1
        url: /widget1.html
      - page: Widget 2
        url: /widget2.html
      - page: Widget 3
        url: /widget3.html


{% for item in %}


{% endfor %}


In this example, Group 1 is the first list item. Within that list item, its subpages are included as a property that itself contains a list. The Liquid code first looks through the first level with for item in, and then looks through the second-level property with for entry in item.subfolderitems. Just as item is arbitrary, so is entry.

Access the list from a page variable

Suppose your sidebar will differ based on different documentation sets. You might have 3 different products on your site, and so you want 3 different sidebars — each being unique for that product.

You can store the name of the sidebar list in your page front matter and then pass that value into the list dynamically.

Page front matter

title: My page
sidebar: toc


{% for item in[page.sidebar] %}
{% for entry in item.subfolderitems %}
<li><a href="{{entry.url}}">{{}}</a></li>
{% endfor %}
{% endfor %}


In order to pass values from the page front matter into an assign variable, when the assigned variable isn’t a string but rather a data reference, you must use brackets (instead of curly braces) to refer to the front matter’s value. For more information, see Expressions and Variables in Liquid’s documentation. Brackets are used in places where dot notation can’t be used (see more details with this Stack Overflow answer.)

Scenario: Apply active class selectively

In addition to inserting items from the YAML data file into your list, you also usually want to highlight the current link if the user is viewing that page. You do this by inserting an active class for items that match the current page URL.

  color: black;
  font-weight: bold;
  cursor: default;



Scenario three: Conditional list

    {% for sec in %} {% if sec.audience == "writers" %}
  • {{sec.url}}
  • {% endif %} {% endfor %}

Scenario: Separate sidebars per page

  • identify sidebar in page frontmatter, and pass that down to set which list gets used

Scenario: Robust Multi-level menu using Navgoco

  • accordion, cookie, 3 level, expand/collapse

loop through json

For loop through pages

see you can do for page in site.html_pages to make the looping faster.

  • no access to categories variable for pages use the uniq tag if you’re getting a list of all pages that have a tag.

you cannot do this:

{% for p in site.categories.mycat %}


basic example:

The code below dynamically generates a sidebar nav of pages with layout: page in the front-matter. See readme for usage.

	            {% assign pages_list = site.pages %}
		          {% for node in pages_list %}
			          {% if node.title != null %}
				            {% if node.layout == "page" %}
					                <a class="sidebar-nav-item{% if page.url == node.url %} active{% endif %}" href="{{ site.baseurl }}{{ node.url  | remove_first: '/' }}">{{ node.title }}</a>
							          {% endif %}
								          {% endif %}
									  {% endfor %}

For the pages we want in the navigation, we’ll add a navigation_weight to the front matter. The value of navigation_weight is a number which dictates the position it’s shown. For index.html we’ll add a navigation_weight of 1.

layout: default title: Home navigation_weight: 1 —

For loops with content stored in different collections

for doc in site.collections[collection_name] ?? site.documents accesses a list of all the documents in every collection

  • load time for for loop through large number of pages is issue

those pages. also maybe provide collections as an example for doing that.