Build a Ready-To-Use Jekyll Setup — Part 3: Dynamic Navigation Menu

Robin Klöckner
5 min readOct 25, 2022

--

Photo by Timothy Muza on Unsplash

Intro

This article is the third part of a series on how to build a Jekyll setup that can be used to develop multi-page websites with static contents in two languages and which are served by an Apache HTTP Server. In the second part we made the website bilingual. However, the navigation menu must be adjusted to work properly.

In This Part

We will add a navigation bar which is dynamically generated during build time, based on a pre-defined list of items. The advantage of a pre-defined list is that we can easily determine just a subset of all available pages to be included, as well as the order of the navigation items and a submenu.

Prerequisites

It is recommended that you follow Part 1 and Part 2 of this guide before proceeding. Alternatively you can download the resulting source code from Part 2 on GitHub, as we will use it as a starting point here.

Current State

After following Part 1 and 2 of this guide, the current folder structure looks as follows:

/
_de/
impressum.html
index.html
_en/
index.html
legal.html
_includes/
footer.html
head.html
header.html
nav.html
scripts.html
_layouts/
default.html
_sass/
base.scss
css/
main.scss
js/
main.js
_config.yml
Gemfile
Gemfile.lock

Additional Pages

We begin this part by adding additional pages to our collections.

In the _de/ directory create the following files with the corresponding content. The Front Matter attributes follow the same structure as described in the second part of this guide.

leistungen.html:

moebel.html:

tueren.html:

In the _en/ directory create the corresponding counterparts with the respective contents.

services.html:

furniture.html:

doors.html:

Note that each new file in the _en/ collection has a corresponding counterpart in the _de/ collection with the same name attribute as described in part two of this guide.

Navigation Menu

We want a solution that makes it easy to define the structure of the navigation menu. The solution should also give us the opportunity to define a submenu, to exclude specific pages from the menu as well as specifying the order of the navigation menu.

A comfortable way of doing this is by defining the structure of the navigation menu in some kind of list. We can use a YAML file for this. By default, Jekyll provides an optional folder, _data/, to host YAML and other file formats which will be accessible during the build process without further configuration.

We will make use of this feature and create a _data folder in the project root directory. Inside the folder create a new YAML file navigation.yml with the following content:

This file defines the structure of the navigation menu. In line 1 we define a name, main, under which the German and the English menus will be available (you can choose a different name if you want). Wrapping the configuration for the navigation menu this way gives us the opportunity to configure multiple navigation menus in the same file.

Within main we create two lists, de and en. Their naming must follow the definition of the collections in _config.yml, i.e. de and en. Otherwise, the next step won’t work.

The items in de and en will define the structure for the German and the English navigation menu. Every item within one of the two lists will represent a navigation item of the respective language. The order of the items is important since the order of the navigation items in the rendered HTML document will be the same.

Each item itself consists of a label and a url variable. The value of the label will be used as the label of the navigation item and can be freely selected. The value of the url will be used to build the reference to the related file. It therefore must match with respective file name within the corresponding collection, plus a leading forward slash (e.g. /doors.html when referencing doors.html from the English collection _en/).

That way we can simply add to or remove pages from the navigation menu, as well as specifying the order of the navigation items.

If we want an item to host a submenu, we can add a third attribute submenu which in turn holds a list of items containing a label and a url, similar as before.

We can now bring everything together in the nav.html file — our HTML template for the navigation menu. What we want is to generate an unordered list <ul> of items based on the pre-defined structure in navigation.yml. When an item contains a submenu, we want the submenu to be an unordered list within the current list <li> element, too.

Therefore, change nav.html as following:

The two links from the previous part are removed. Instead we loop over the list of navigation items as defined in navigation.yml, which corresponds to the language of the current page. We do that with a for-loop in line 3.

site.data.navigation.main[page.lang] can be interpreted as following: site is a Jekyll variable that gives us access to the _data/ folder and the navigaton.yml file. In navigation.yml we access the main variable which we used to wrap the German and the English navigation menu. We then use the language code defined in the Front Matter of the current page, page.lang, to access the list of menu items that corresponds to the current language.

For each item of the selected list we create an anchor element <a> within a list element <li> (line 4 to 7). The value of the href attribute is build by concatenating the baseurl from the _config.yml, the language code of the current page (page.lang) and the file name of the current item as defined in the url attribute within navigation.yml. The label is also taken from label attribute of the current item.

If any item contains a submenu (checked in line 9) a second unordered list is generated by looping the nested list of submenu items, similar as before.

In addition, we add an additional CSS class for the item that contains a submenu in order to give it a different styling or behavior if needed (line 4).

Result

We now have the following folder structure:

/
_data/
navigation.yml
_de/
impressum.html
index.html
leistungen.html
moebel.html
tueren.html
_en/
doors.html
furniture.html
index.html
legal.html
services.html
_includes/
footer.html
head.html
header.html
nav.html
scripts.html
_layouts/
default.html
_sass/
base.scss
css/
main.scss
js/
main.js
_config.yml
Gemfile
Gemfile.lock

Running bundle exec jekyll serve in your terminal now builds and serves the website under http://127.0.0.1:4000.

Illustration: Result of part 3

The navigation is now dynamically generated according our pre-defined list in navigation.yml and works as expected. Regardless on which page the language is toggled, the same page is loaded in the alternative language.

Source Code

GitHub: Jekyll setup - Part 3

In the Next Part

We build a configuration file for a virtual host of an Apache HTTP Server in order to serve the website in the language that corresponds to the language set in the Accept-Language header field of the HTTP request.

MOVE TO PART 4

--

--