2

We have a custom menu mymenu where we use menu_link_attributes to add CSS classes per menu link.

The problem we are running into is that we have one generic css class that we always want added regardless of whether it is entered through the Menu link attributes. In the twig template, it is using {{ link(item.title, item.url) }}.

We tried the following, but it will only replace myCssClass with whatever was their before and I cannot seem to find the right array when calling mymodule_preprocess_menu().

{{ link(item.title, item.url, item.attributes.addClass('myCssClass')) }}

How can I append a CSS class to a menu link to the item.attributes array?

menu--mymenu.html.twig

{{ 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('menu') }}>
    {% else %}
      <ul class="menu">
    {% endif %}
    {% for item in items %}
      {%
        set classes = [
          'menu-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) }}>
        {{ link(item.title, item.url) }}
        {% if item.below %}
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
        {% endif %}
      </li>
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

2 Answers 2

3

This is an easy one, I'm pretty sure you might have figured out yourself in a short while.

You see that set classes directive?

{%
  set classes = [
    'menu-item',
    item.is_expanded ? 'menu-item--expanded',
    item.is_collapsed ? 'menu-item--collapsed',
    item.in_active_trail ? 'menu-item--active-trail',
  ]
%}

This is where the magic happens and the classes array is built for all CSS classes to attach to your link item(s).

And this is also the place where you should add your additional CSS class that should be used in every link item, like so:

{%
  set classes = [
    'myCssClass',
    'menu-item',
    item.is_expanded ? 'menu-item--expanded',
    item.is_collapsed ? 'menu-item--collapsed',
    item.in_active_trail ? 'menu-item--active-trail',
  ]
%}

Leaving the rest of the template untouched (especially the {{ item.attributes.addClass(classes) }}) gives you the desired behavior.

Some further reading, that might be of interest for you: https://www.drupal.org/docs/8/theming-drupal-8/using-attributes-in-templates

1
  • yes this was an easy one and i felt really bad after finding the solution because it was staring me in the face. I was overthinking this. Aug 7, 2018 at 0:32
3

This is a little bit trickier because — as you can see — there are no anchor tags in the template. But there is the link() function instead. We have to add the class to this.

We also have to remove the menu item classes because they are leaking.

{% for item in items %}

      <li{{ item.attributes.addClass('nav-item') }}>
        {{ link(item.title, item.url, item.attributes.addClass('nav-link').removeClass('nav-item') ) }}
        {% if item.below %}
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
        {% endif %}
      </li>
    {% endfor %}

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.