eleventy-navigation
eleventy-navigation copied to clipboard
active class on parent
Thanks for this wonderful plugin and love eleventy. But is there a way I can get active class on the parent selecter ?
You can do it by checking if entry.url == page.url
E.g.:
<nav id="menu">
{% set pages = collections.all | eleventyNavigation %}
<ul>
{%- for entry in pages %}
<li{% if entry.url == page.url %} class="current"{% endif %}>
<a href="{{ entry.url | url }}">{{ entry.title }}</a>
</li>
{%- endfor %}
</ul>
</nav>
@p44v9n it just compares item.url to current page.url
I think OP asked for having a current/active class if navigation element page is parent of current page
it really difficult (or impossible?) to access a template's (aka page's) parent (and other user defined data) in a layout which isnt associated with the template like _base.njk oder _header.njk
After 2 hours of reading and trying
This https://www.11ty.dev/docs/data/
and This https://www.mikeaparicio.com/posts/2022-08-19-nested-navigation-in-eleventy/
I ended up with using plain path parsing (works only for first level)
// eleventy.config.js
const path = require("path");
module.exports = function (eleventyConfig) {
eleventyConfig.addFilter("getbase", function (value) {
const { dir } = path.parse(value);
return dir + "/";
});
}
{# layout #}
<nav class="main-navigation">
{% set navPages = collections.all | eleventyNavigation %}
<ul>
{%- for entry in navPages %}
<li{% if entry.url == page.url or entry.url == page.url | getbase %} class="current"{% endif %}>
<a href="{{ entry.url }}">{{ entry.title }}</a>
</li>
{%- endfor %}
</ul>
</nav>
Building upon @scsskid's code, this is working right now for me with 3~4 sub dirs. I was only interessted if the top dir matched the menu item associated.
getbase: function (value) {
if (value!==false) {
const {dir}=path.parse(value);
const firstPath=dir.split('/')[1];
return "/"+firstPath+"/";
} else {
// Handle the case where value is a boolean false
return "Invalid input: value is false";
}
},
that ugly value!==false there is because i started having errors with navigation items that didn't have pages (they redirect to another url).
It's ugly and only works for top level but this option doesn't require a filter:
{% set navPages = collections.all | eleventyNavigation %}
{% set navActiveClass = "is-active" %}
{%- for navItem in navPages %}
{% if (navItem.url == "/") %}
<li {% if navItem.url == page.url %}class="{{navActiveClass}}"{% endif %}>
<a href="{{ navItem.url }}">{{ navItem.title }}</a>
</li>
{% elif navItem.url and page.url %}
<li{% if navItem.url in page.url %} class="{{navActiveClass}}"{% endif %}>
<a href="{{ navItem.url }}">{{ navItem.title }}</a>
</li>
{% endif %}
{%- endfor %}
The key is if navItem.url in page.url, check that the parent URL exists in the current URL. This should be unique for all top level URL. Unfortunately, the home link / exists in all URL so we have to check for that first.
Edit: replaced {% else %} with {% elif navItem.url and page.url %} as the build broke if a post was in draft.
This is now possible with the CSS :has selector, which let you style elements based on their children, see https://developer.mozilla.org/en-US/docs/web/css/:has
li:has(.activeClass)
in my own markup, i didn’t have parent child relationships, but i was able to use
{% if item.url in page.url %} to add a class to a page’s parent’s link. @patrickgrey gave me the idea.
<a class="nav-item has-children
{% if item.url == page.url %}active{% endif %}
{% if item.url in page.url %}active{% endif %}"
href="{{ item.url }}" {% if item.url == page.url %}aria-current="page"{% endif %}>
{{ item.title }}
</a>