Menu item does not have "active" class when the menu item page is open.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

faizalluthfi created an issue. See original summary.

markhalliwell’s picture

Component: User interface » Templates
Issue tags: -menu item
Related issues: +#2634054: Menu Level 2+ not working
markhalliwell’s picture

Title: Please add "active" class to menu item » Add "active" class to menu item
CRZDEV’s picture

Drupal core adds the active class into links through javascript (located in /core/misc/active-link.js) using the data-attribute "data-drupal-link-system-path" with the referenced path value.

Bootstrap wants the active class in the menu item element <li>, there are two ways to solve this;

- One would be using js, adding the link class to the menu item parent element.
- Other consists into adding class into menu preprocess function:

/**
 * Pre-processes variables for the "menu" theme hook.
 *
 * @ingroup theme_preprocess
 *
 * @BootstrapPreprocess("menu")
 */
class Menu extends PreprocessBase implements PreprocessInterface {

  /**
   * {@inheritdoc}
   */
  public function preprocessVariables(Variables $variables, $hook, array $info) {

    $current_path = \Drupal::service('path.current')->getPath();

    foreach ($variables['items'] as $item) {
      /** @var \Drupal\Core\Url $url */
      $url = $item['url'];
      if ($url->isRouted()) {
        $system_path = $url->getInternalPath();
        $item->is_active = $current_path == '/' . $system_path ? TRUE: FALSE;
      }
    }

    $this->preprocessAttributes($variables, $hook, $info);
  }
}

And adding it into twig template:

{%
    set classes = [
       item.is_active ? 'active',
    ]
%}

But this way it only works into first menu level, is needed to deep into each menu item and search for other menus (recursively).
Any suggestions?

Macronomicus’s picture

This can be done with twig too, after some investigation and tweaking for bootstrap theme I got it to work, might need more cleanup YMMV :)
Copy menu--main.html.twig from the bootstrap theme and add to your subthemes templates folder with the following changes.

{#
/**
 * @file
 * Default theme implementation to display a menu.
 *
 * Available variables:
 * - menu_name: The machine name of the menu.
 * - items: A nested list of menu items. Each menu item contains:
 *   - attributes: HTML attributes for the menu item.
 *   - below: The menu item child items.
 *   - title: The menu link title.
 *   - url: The menu link url, instance of \Drupal\Core\Url
 *   - localized_options: Menu link localized options.
 *   - is_expanded: TRUE if the link has visible children within the current
 *     menu tree.
 *   - is_collapsed: TRUE if the link has children within the current menu tree
 *     that are not currently visible.
 *   - in_active_trail: TRUE if the link is in the active trail. 
 *
 * @ingroup templates
 */
#}
{% import _self as menus %}

{#
  We call a macro which calls itself to render the full tree.
  @see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}

{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
      <ul id="menu" {{ attributes.addClass('navbar-list','menu', 'nav', 'navbar-nav') }}>
    {% else %}
      <ul {{ attributes.addClass('dropdown-menu') }}>
    {% endif %}
    {% for item in items %}
        {%
        set classes = [
        'navbar-item',
        item.is_expanded ? 'menu-item--expanded',
        item.is_expanded ? 'dropdown',
        item.is_collapsed ? 'menu-item--collapsed',
        item.in_active_trail ? 'menu-item--active-trail',
        item.in_active_trail ? 'active',
        ]
        %}
      {% if menu_level == 0 and item.is_expanded %}
        <li{{ item.attributes.addClass( classes,'expanded', 'dropdown') }}>
        <a href="{{ item.url }}" class="navbar-link dropdown-toggle" data-target="#" data-toggle="dropdown"> {{ item.title }} <span class="caret"></span></a>
      {% else %}
        <li{{ item.attributes.addClass( classes,'item') }}> 
        {#{{ link(item.title, item.url) }}#} 
        {{ link(item.title, item.url, { 'class':['navbar-link']}) }}
      {% endif %}
      {% if item.below %}
        {{ menus.menu_links(item.below, attributes.removeClass('nav', 'navbar-nav'), menu_level + 1) }}
      {% endif %}
      </li>
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

Also you'll need the .menu-item--active-trail bit in your css, so if items in the dropdown are active sets the parent trail as active too.

.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus ,
.navbar-default .navbar-nav > .menu-item--active-trail > a,
.navbar-default .navbar-nav > .menu-item--active-trail > a:hover,
.navbar-default .navbar-nav > .menu-item--active-trail > a:focus  {
    color: #fff;
background-color: #272727 !important;
}
davy-r’s picture

Status: Active » Needs review
FileSize
2.85 KB

I received a bug report "It doesn't work with Bootstrap", for the Menu Trail By Path module, which lead me to this issue.

I created a patch based on the idea of #5.

csedax90’s picture

Patch #6 works like a charm

vistree’s picture

Patch in #6 works great - an absolute need!!!

kevinwal’s picture

#6 works great. Thanks!

seworthi’s picture

Fixed formatting of set command to match style in other bootstrap templates.

Works great.

jorgediazhav’s picture

Status: Needs review » Reviewed & tested by the community

Works pretty well.

  • markcarver committed 3bd85ff on 8.x-3.x authored by davy-r
    Issue #2643538 by seworthi, davy-r: Add "active" class to menu item
    
markhalliwell’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

lukasss’s picture

Right now I have not worked it!
I do so:
1) Install drupal 8
2) Enable view "glossary"
3) drush dl bootstrap
4) Set as default bootstrap theme
3) When I visit "glossary", I see:

<li>
  <a href="/glossary" data-drupal-link-system-path="glossary" class="is-active">Glossary</a>
</li>

Only when I add a link to "/glossary" on page /admin/structure/menu/manage/main/add I see:

<li class="active">
  <a href="/glossary" data-drupal-link-system-path="glossary" class="is-active">2 glossary</a>
</li>

I don't know if this related problem with Tim's question or views?

TLWatson’s picture

@lukasss - I am having the same problem, specifically for a Glossary view. I believe it's related to this issue, not Bootstrap:
https://www.drupal.org/node/2820751