Feb 23. 2019 · by Helge Sverre

Active menu links in CraftCMS with Twig macros and more

Option 1 - Twig Macros and request segments

This option is great if you have a navigation where the there might be subpages, but you only want to make the "top level" navigation item active.

Example:

Your site consist of the following pages:

  • Home
  • Blog
    • blog post 1
    • blog post 2
    • About
  • Services
    • Service 1
    • Service 2

When someone is on the "blog post 1" page, you only want to mark the "Blog" menu item as active.

Here is a simple way to do just that, shamelessly stolen from this Stackoverflow thread (adapted for Craft 3, as that answer will trigger a deprecation warning in Craft 3)

templates/_macros.twig
TWIG
{% macro is_active(segment) %}
	{% if craft.app.request.segments | first == segment %}active{% endif %}
{% endmacro %}

And you import and use the macro like so:

templates/_layout.twig
TWIG
{% import "_macros.twig" as macros %}

<nav>
    <ul>
        <li><a href="/" class="{{ macros.is_active('') }}">Home</a></li>
        <li><a href="/blog" class="{{ macros.is_active('blog') }}">Blog</a></li>
        <li><a href="/about" class="{{ macros.is_active('about') }}">About</a></li>
        <li><a href="/services" class="{{ macros.is_active('services') }}">Services</a></li>
    </ul>
</nav>

The "first segment" in the context of Craft's request, means the first word of the URL after the first /.

A URL (Uniform Resource Location) is broken into different parts, each with its own name, explaining all of the parts is beyond the scope of this article, so check the wikipedia article, here are some simple examples that relates to what we are trying to do:

The first segment is in bold

  • https://startingcraft.com/articles/active-menu-links-in-craftcms
  • https://craftquest.io/courses/how-to-create-craft-plugin
  • https://craftcms.stackexchange.com/questions/554/how-can-i-add-a-dynamic-active-css-class-to-the-navigation-on-any-given-page

Note: For the homepage, you pass an empty string ("") as there is no segments.

Option 2 - Checking the entry id

This approach is useful for instances where you want to add an active class to entry links, you might use this if you are building a knowledge base or documentation site where you have all entries in a section in the sidebar, and want to show which one you are currently on.

templates/article/_entry.twig
TWIG
<div class="wrapper">
    <article class="content">
        <h1>{{ entry.title }}</h1>
        <div>{{ entry.content }}</div>
    </article>
    <aside class="sidebar">
        <h1>Articles</h1>
        <ul>
            {% for article in craft.entries.section('articles') %}
                <li class="{{ article.id == entry.id ? 'active' }}">
                    <a href="{{ article.url }}">{{ article.title }}</a>
                </li>
            {% endfor %}
        </ul>
    </aside>
</div>

Option 3 - The Sprout Active Plugin

There is a great plugin from Barrel Strength Design called Active that simplifies all of this active checking logic for you, you can read the documentation here, I think their documentation explains how to use it better than I can, so check it out.

Hope this article was useful to you. :)

References and links in this article