1

I have following scenario: Drupal 8.5.6, with a bootstrap subtheme. There are 2 menus (I'll call them main menu and secondary menu).

The links in the main menu are geographic areas, I've managed to add the .active class to the link, based on the url with the help of this answer: https://drupal.stackexchange.com/a/191861/60589 with a preprocess function and tweaking the twig code.

The links in the secondary menu are related to each one of the links in the main menu, so when I click Area 1 in the main menu, a custom secondary menu will appear in this page.

The problem: I want the main menu link to stay highlihted, when I click on a link of the secondary menu The URLs look like this:

mysite/areas/area1 ==> the Area1 link in the main menu gets the active class

mysite/areas/area1/otherlink ==> the links in the secondary menu have this structure, I want the Area1 link in the main menu to keep the .active class.

1 Answer 1

3

The cited solution appears a little buggy, as it replaces all potentially existing classes of the menu items. But what makes it not suitable for your use case is, that it is intended to add the active class only, if the current path matches the menu link's URL path.

What you are looking for instead, is the menu items' "active trail". It is a flag set by the menu module on every menu item found when traversing the menu tree upwards, starting from the current active item up to the menu root.

With this information at hand, have a check for the default menu template. It features the menu item specific property in_active_trail:

in_active_trail: TRUE if the link is in the active trail.

So you can easily add the active class to your currently active menu item and all its parents by using the following in your theme's menu.html.twig:

{%
  set link_classes = [
    item.in_active_trail ? 'active',
  ]
%}
{{ link(item.title, item.url, {'class': link_classes}) }}

A more complete example for a Bootstrap 4 navigation with menu.html.twig:

{#
/**
 * @file
 * Theme override to display a Bootstrap 4 menu.
 */
#}
{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0) }}
{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
      <ul{{ attributes.addClass('nav') }}>
    {% else %}
      <ul class="menu">
    {% endif %}
    {% for item in items %}
      {%
        set classes = [
          'nav-item',
          item.is_expanded ? 'menu-item--expanded',
          item.is_collapsed ? 'menu-item--collapsed',
          item.in_active_trail ? 'menu-item--active-trail',
        ]
      %}
      <li{{ item.attributes.addClass(classes) }}>
        {%
          set link_classes = [
            'nav-link',
            item.in_active_trail ? 'active',
          ]
        %}
        {{ link(item.title, item.url, {'class': link_classes}) }}
        {% if item.below %}
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
        {% endif %}
      </li>
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}
1
  • 1
    Thanks Mario, I had to test the code, but from the moment I read your answer, I knew it was right. Aug 25, 2018 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.