automated navigation menus from data files

Why Manual Navigation Is a Problem As your documentation grows in scale and complexity, manually updating navigation menus becomes error-prone and time-consuming. Every time you add a new page or rename a section, you must update multiple navigation structures, often across several files or versions. This redundancy is a breeding ground for inconsistency. To solve this, Jekyll allows the use of YAML data files to drive content generation dynamically. This enables you to define navigation structures once and reuse them across multiple versions, templates, or layouts. Setting Up Data-Driven Navigation Step 1: Create a Data File Create a new file called _data/navigation.yml in your Jekyll root. Here's a basic structure: v1: - title: Getting Started url: /v1/getting-started/ - title: API Reference url: /v1/api/ v2: - title: Introduction url: /v2/introduction/ - title: Usage url: /v2/usage/ - title: API Reference url: /v2/api/ This organize...

automated navigation menus from data files

Why Manual Navigation Is a Problem

As your documentation grows in scale and complexity, manually updating navigation menus becomes error-prone and time-consuming. Every time you add a new page or rename a section, you must update multiple navigation structures, often across several files or versions. This redundancy is a breeding ground for inconsistency.

To solve this, Jekyll allows the use of YAML data files to drive content generation dynamically. This enables you to define navigation structures once and reuse them across multiple versions, templates, or layouts.

Setting Up Data-Driven Navigation

Step 1: Create a Data File

Create a new file called _data/navigation.yml in your Jekyll root. Here's a basic structure:

v1:
  - title: Getting Started
    url: /v1/getting-started/
  - title: API Reference
    url: /v1/api/
v2:
  - title: Introduction
    url: /v2/introduction/
  - title: Usage
    url: /v2/usage/
  - title: API Reference
    url: /v2/api/

This organizes navigation by version. Each version has an array of pages, each with a title and url.

Step 2: Render Menus Dynamically in Layouts

In your default.html or sidebar.html layout, add the following Liquid logic to pull navigation dynamically based on the current page’s version:

{% assign current_version = page.version %}
{% assign menu = site.data.navigation[current_version] %}

<nav class="sidebar-nav">
  <ul>
    {% for item in menu %}
      <li><a href="{{ item.url }}">{{ item.title }}</a></li>
    {% endfor %}
  </ul>
</nav>

This approach ensures each version displays its relevant navigation without having to manually hard-code anything.

Supporting Nested Navigation

To support deeper structures (like categories with children), modify your YAML file like this:

v2:
  - title: Introduction
    url: /v2/introduction/
  - title: Guides
    children:
      - title: Installation
        url: /v2/guides/installation/
      - title: Configuration
        url: /v2/guides/configuration/
  - title: API
    url: /v2/api/

Then render it with recursive Liquid logic:

{% assign menu = site.data.navigation[page.version] %}

<ul>
  {% for item in menu %}
    <li>
      <a href="{{ item.url | default: '#' }}">{{ item.title }}</a>
      {% if item.children %}
        <ul>
          {% for child in item.children %}
            <li><a href="{{ child.url }}">{{ child.title }}</a></li>
          {% endfor %}
        </ul>
      {% endif %}
    </li>
  {% endfor %}
</ul>

This method can handle multiple layers of nesting, such as sections and subsections. You can also add icons or custom attributes for advanced rendering.

Using Includes for Clean Code

To avoid cluttering your layout, move the navigation logic to an include:

_includes/sidebar.html
{% assign menu = site.data.navigation[page.version] %}

<ul>
  {% for item in menu %}
    <li>
      <a href="{{ item.url | default: '#' }}">{{ item.title }}</a>
      {% if item.children %}
        <ul>
          {% for child in item.children %}
            <li><a href="{{ child.url }}">{{ child.title }}</a></li>
          {% endfor %}
        </ul>
      {% endif %}
    </li>
  {% endfor %}
</ul>

Then call it in your layout with:

{% include sidebar.html %}

Making the Navigation Responsive to Active Page

You can highlight the current page in your navigation by comparing URLs:

{% if item.url == page.url %} class="active" {% endif %}

Apply it inside your anchor tag to style the current page link.

Version-Independent Navigation Structures

If your documentation shares structure across versions, you can avoid repeating navigation trees by abstracting common parts into a base YAML file like _data/nav_common.yml. Then, use a version-specific override if needed.

Example:

{% assign menu = site.data.nav_override[page.version] | default: site.data.nav_common %}

Case Study: Combining Search, Versions, and Navigation

Imagine you're running documentation for a multi-version SaaS API. Here's how all components integrate:

  • Search: You index all versions using a build-time script, injecting version in each JSON entry.
  • Navigation: You define shared structure in nav_common.yml and override where necessary.
  • Page Metadata: Each Markdown file includes version and slug front matter for dynamic linking.

This results in a fully dynamic, consistent, and scalable static documentation system.

Benefits of Data-Driven Menus

  • Consistency: All versions follow the same structure unless specifically overridden
  • Maintainability: Updating navigation requires only one file edit
  • Automation: You can generate or validate YAML with CI pipelines

Going Further

To push automation further, consider using YAML anchors for reuse within files, or even generating YAML programmatically from directory structures during build time with custom scripts.

Conclusion

Using data files to manage Jekyll navigation allows you to maintain consistency, reduce errors, and adapt quickly to structural changes—especially across versioned documentation. This approach is highly scalable and aligns well with static site philosophies like those behind GitHub Pages.

Next, we’ll explore how to integrate client-side search (like Lunr.js) into your documentation site, combining structured content with dynamic discovery to create a complete documentation platform.


Archives / All Content


© MintTagReach🕒😃😃😃 . All rights reserved.