5

I've added a custom twig template for links--language-block.html.twig.

Inside of it, I want to render additional HTML when the current item is active. But I can't figure out how to check when the current item is active.

{% if links -%}
  {%- if attributes.hasClass('inline') -%}
  <ul{{ attributes.addClass('list-inline') }}>
  {%- else -%}
  <ul{{ attributes }}>
  {%- endif -%}
    {%- for key, item in links -%}

      {% if item.attributes.hasClass('is-active') %} << this is always false
        <li>foobar</li>
      {%- endif -%}

      <li{{ item.attributes.addClass('dropdown') }}>
        {%- if item.link -%}
          {{ item.link }}

          {# <a class="dropdown-toggle" data-target="#" data-toggle="dropdown">Deutsch <span class="caret"></span></a> #}
        {%- elseif item.text_attributes -%}
          <span{{ item.text_attributes }}>{{ item.text }}</span>
        {%- else -%}
          {{ item.text }}
        {%- endif -%}
      </li>
    {%- endfor -%}
  </ul>
{%- endif %}

How can I check if the link as the active class?

8
  • 1
    When you inspect element, do you see the is-active class?
    – No Sssweat
    May 23, 2016 at 14:32
  • @NoSssweat in the end result yes, but not in the twig template. even using kint the final a tag has not the active class, only in the browser. it is not javascript, i've checked that
    – Alex
    May 24, 2016 at 6:29
  • An alternative would be to get the current page url or the node title and use that as your if statement.
    – No Sssweat
    May 24, 2016 at 7:17
  • Having the same issue. Did you manage to figure out why this is not working? Jun 10, 2016 at 14:00
  • 1
    @leymannx, yes, this is the best choice. For anonymous requests there is also a PHP option in a response subscriber, see drupal.stackexchange.com/a/235108/47547
    – 4uk4
    Jul 24, 2019 at 16:18

5 Answers 5

3
+75

In some cases, the active state is not set by design due potential problems with caching. This behavior is documented in this change record.

Setting the active class is now an opt-in feature:

l() and LinkGenerator::generate() now have a set_active_class option that defaults to FALSE theme_links() now accepts a set_active_class key that defaults to FALSE Those links that you'd expect to get the active class set, do get it: menu links, language switching links …

The output of l(), LinkGenerator::generate() and theme_links() no longer contains the active class, even if you do opt in. Instead, they get a data-drupal-link-system-path attribute, and if there's a GET query, they also get a data-drupal-link-query attribute…

In those cases, where it is not set on server side, you can take a look at core/misc/active-link.js to get an idea how to manipulate the active state on client side.

1
  • Yes this behaviour can be confusing to those of us used to how things worked in previous versions of Drupal. Wasted a lot of time figuring this out for myself. Jul 25, 2019 at 14:29
1

It seems you can just use "is_active". This works for me:

{% set link = link|merge({ '#attributes': { 'class': [ 'classes', 'if', 'active'] } }) %}
{% if is_active %}
{% set link = link|merge({ '#attributes': { 'class': [ 'classes', 'if', 'not', 'active'] } }) %}
{% endif %}

<li{{ attributes.addClass('nav-item') }} role="presentation">{{ link }}</li>
2
  • Really? Even in a cached and unauthenticated session?
    – leymannx
    Jul 24, 2019 at 17:53
  • Cant find a menu where I use this where the user is not logged in. Will get back to you if I find a case. Jul 24, 2019 at 17:59
1

In Drupal 8 the "is-active" class is added in two different ways:

  • For anonymous users it's added in the server side.
  • For authenticated users it's using javascript to add the class, as this allows for better cacheability.

You might consider adding the <li> in JS when the DOM is ready, to make sure the class has been added to the DOM.

0

For core/themes/classy/templates/navigation/menu.html.twig:

{#
/**
 * @file
 * Theme override 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.
 */
#}

Then you can write:

{% if item.in_active_trail %}
   <li>foobar</li>
{% endif %}
0

Define a JS library with a dependency on the core/drupal.active-link library:

mytheme/mytheme.libraries.yml

remove-active-links:
  version: 1.x
  js:
    js/remove-active-links.js: { }
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.active-link

Then your JS code knows which link has an is-active class and you can add HTML or remove the link wrapper like in this example:

mytheme/js/remove-active-links.js

(function ($, Drupal) {

  'use strict';

  Drupal.behaviors.removeActiveLinks = {
    attach: function (context) {

      $(context).find('a.is-active').contents().unwrap();

    }
  };

})(jQuery, Drupal);

For more info and an alternative PHP solution (only for anonymous requests) see this answer Don't link menu in the active page

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.