Keenan Payne
Keenan Payne

Reputation: 816

Setting active links in Jekyll not working

I am trying to simply style my active links in Jekyll but have been unsuccessful in getting them working.

Here is the site that I am trying to get them working on: http://concisecss.github.io/concise.css, which you can see the source code for here: https://github.com/ConciseCSS/concise.css/tree/gh-pages.

I am putting this YAML code in my _config.yml to define my top-level navigation:

# Main Navigation
nav:
- text: Welcome
  url: /concise.css/
- text: Why Concise
  url: /concise.css/why-concise/
- text: Get Started
  url: /concise.css/get-started/
- text: Documentation
  url: /concise.css/documentation/layout/container/
- text: Add-Ons
  url: /concise.css/add-ons/

Then in my header.html include, which is where my navigation is, I have:

{% for link in site.nav %}
  <li>
    <a {% if link.url == page.url %}class="active"{% endif %} href="{{ link.url }}">{{ link.text }}</a>
  </li>
{% endfor %}

However, whenever I am on one of those navigation links, the active class is not added (the link should be pinkish when you are on it.

Everything else is working fine, so I'm assuming it might just be a small issue I'm running into.

Edit: Here is what the front-matter on one of my pages looks like:

---
layout: why-concise
title: Why Concise
permalink: /why-concise/
---

Upvotes: 4

Views: 1523

Answers (2)

Dexter
Dexter

Reputation: 9324

Sep 2023

I believe this question is resolved.
It's 2023, and we still have this issue. So, if anyone is looking for a solution, here it is.

I am using ruby 3.3.2 and jekyll 4.3.2

DRY: Don't Repeat Yourself

.md files are converted to .html when they compile.
Let's start with simple navigation. I have created three menus in the _config.yml file.

nav:
- title: Home
  url: /
- title: About
  url: /about/
- title: Contact
  url: /contact/

Frontend

After compiling, this is how it looks. Even though the pages all work fine, if you notice, none of the files have the .html extension.

<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about/">About</a></li>
    <li><a href="/contact/">Contact</a></li>
</ul>

Original URL

If you output {{ page.url }}, you will see .html attached to each of the links.

/
/contact.html
/about.html

Issue

What you are doing here is comparing /pagename/ to /pagename.html. How will this work? It will work only on the homepage because the homepage for both page.url and link.url is a slash /.

So, How to fix this?

Solution 1

You have to include .html in all the URLs. This will fix the issue.

# Main Navigation
nav:
- text: Home
  url: /
- text: About
  url: /about.html
- text: Contact
  url: /contact.html

Solution 2

If you have a simple site, you could output all the pages directly using site.pages. Since all the pages have a 'title', you can use that property. But before that, let's output all of them by URL.

Output all url

<ol>
    {% for key in site.pages %}
        <li>{{key.url}}</li>
    {% endfor %}
</ol>

Notice that all the URLs have .html attached, except for the fourth one, which is 'Home'.

<ol>
    <li>/404.html</li>
    <li>/about.html</li>
    <li>/contact.html</li>
    <li>/</li>
    <li>/assets/main.css</li>
    <li>/feed.xml</li>
</ol>

Output by title

Let's output all the titles for the pages. I am assuming all the titles are set in the Front Matter.

<ol>
    {% for key in site.pages %}
        <li>{{key.title}}</li>
    {% endfor %}
</ol>

Notice that some of the files do not have a title. The ones that have the title are needed for the website.

<ol>
    <li></li>
    <li>About</li>
    <li>Contact</li>
    <li>Home</li>
    <li></li>
    <li></li>
</ol>

Filter by title

Now let's use an if condition to filter the files that have a title.

<ol>
    {% for key in site.pages %}
    {% if key.title %}
        <li>{{key.title}}</li>
    {% endif %}
    {% endfor %}
</ol>

This outputs the following

<ol>
    <li>About</li>
    <li>Blog</li>
    <li>Contact</li>
    <li>Home</li>
</ol>

Conclusion

Here's the final menu. Now you can use the active class condition; it should work on all menus.

<ol>
    <li><a href="/about.html">About</a></li>
    <li><a href="/blog.html">Blog</a></li>
    <li><a href="/contact.html">Contact</a></li>
    <li><a href="/">Home</a></li>
</ol>

Upvotes: 1

Adriano Rosa
Adriano Rosa

Reputation: 8761

I just did the same thing in my blog project which is not alive yet to show you, but it works like this:

1. create a data file nav.yml file and write your nav text and URLs within a folder _data.

nav.yml

- text: Welcome
  url: /concise.css/

- text: Why Concise
  url: /concise.css/why-concise/

- text: Get Started
  url: /concise.css/get-started/

- text: Documentation
  url: /concise.css/documentation/layout/container/

- text: Add-Ons
  url: /concise.css/add-ons/

2. In your html page you're going to create a loop through your data menu list from yml file.

{% for nav in site.data.nav %}
<li{% if nav.url == page.url %} class="active"{% endif %}><a href="{{ nav.url }}">{{ nav.text }}</a></li>
{% endfor %}

Just remember to make sure your permalink is the same written in your nav.yml if you have set url:/concise.css/why-concise/ in your nav.yml so your permalink should be the same in the front-matter.

---
layout: why-concise
title: Why Concise
permalink: /concise.css/why-concise/
---

UPDATE: @Keenan here is an example http://adrianorosa.com, that I told you before. The source can be found at https://github.com/adrianorsouza/adrianorosa.com

Upvotes: 3

Related Questions