17

I want to add a class to the <a> tag of a field that consists of a link and text. (It's a field of type Link.) The name of the field is content.field_c_button_link.

In the template file, I want to add something like the following.

{{ content.field_c_button_link.0.addClass('button blue') }}

How can I add a class properly?

According to Patrick Scheffer's answer, I looked at the settings for a field where I can add extra CSS classes, but I could not find any. This is a screenshot of what I can edit in the link field.

screenshot

10 Answers 10

11

This is a solution I found, but it isn't really handy to use... I really want a better solution, like something directly from twig templates.

function template_preprocess_field(&$variables, $hook) {
  $element = $variables['element'];
  if ($element['#name'] == 'field_c_button_link') {
    $variables['items'][0]['content']['#options']['attributes']['class'][] = 'button';
  }
}
1
  • 5
    It should be '#field_name' instead of '#name'.
    – leymannx
    Dec 4, 2017 at 21:34
7

The easiest way to achieve this would be by using either of these two modules.

1.Link Class - Link class module provide a new widget form for field type Link. This widget allows editor to add class to fields Link attached to their content.

2.Link Attributes - Link attributes widget provides an additional widget for the link field found in Drupal core. The widget allows users to set attributes on their link.

In addition the module alters the default menu link content link field to use this widget, allowing menu links to have attributes too

id, class, name, target, rel, accesskey

Once either of the two are enabled we can set the widget settings for the "Link" field under "Manage Form Display" for the particular link field.

See attached image for reference.

enter image description here

Once this is set enter each class separated by a space in the field that appears at the time of content creation.enter image description here

1
  • 1
    Many thanks for the detailed write up, very helpful. Both good solutions.
    – ymdahi
    Jun 14, 2019 at 14:52
5

If you edit that link field in your content type (admin/structure/types/manage/your_contenttype/fields/field_c_button_link), there's a field Extra CSS-classes.

However, the classes entered here apply to all links created with 'field_c_buton_link'. If you want to add a class on one specific location, you might take a look at hook_preprocess_field] or even theme_link.

Edit:

In Drupal 8 there is also a theme_preprocess_field. So I think you can do something like this:

function template_preprocess_field(&$variables, $hook) {
  $element = $variables['element'];
  if ($element['#name'] == 'field_c_button_link') {
    $variables['attributes']['class'][] = 'button';
    $variables['attributes']['class'][] = 'blue';   
  } 
}

I haven't tested this so I think you need to make some adjustments to make this work.

9
  • Thanks for your answer but I can not find such field... :(
    – maidi
    Nov 19, 2015 at 12:17
  • Which fields are available when editing the link field? Nov 19, 2015 at 12:23
  • I added a Screenshot to my question
    – maidi
    Nov 19, 2015 at 12:26
  • I see, what version of the link module do you use? Nov 19, 2015 at 12:27
  • Where can I find out? I use Drupal 8 so the Link module was part of the core.
    – maidi
    Nov 19, 2015 at 12:32
5

To do this in twig using the field template (i.e. field--field-c-button-link.html.twig )

Normally the field template will loop over your link(s) using:

  {% for item in items %}
    {{ item.content }}
  {% endfor %}

But you can change that to something like this:

  {% for item in items %}
    <a class="btn btn-secondary btn-lg m-1" href="{{ item.content['#url'] }}">{{ item.content['#title']}}</a>
  {% endfor %}

by dealing with the link title and url separately.

4

To add to Tony Fisler's answer above, in Drupal 8.1.2 I needed to check for #field_name instead of name to add a class. This is what works for me.

function yourthemename_preprocess_field(&$variables, $hook) {
  $element = $variables['element'];
  if ($element['#field_name'] == 'field_link') {
    $variables['items'][0]['content']['#options']['attributes']['class'][] = 'blarg';
  }
}

This is if you want the class on the <a> tag. The link class solution offered is easier, but when I tried it only applied to class to the wrapper of the a. So, if you're using Bootstrap for example, the link class module wouldn't work.

1
  • 1
    Thanks! This is very helpful, but presumes the field only has one item. If the field has multiple items you need to loop through them. e.g. if ($element['#field_name'] == 'field_link') { foreach ($variables['items'] as $key => $item){ $variables['items'][$key]['content']['#options']['attributes']['class'][] = 'blarg'; } } Dec 16, 2016 at 12:36
2

You can use Project Link class which permit to add classes on Link field. You should set the widget to "Link with class". See screenshot. enter image description here enter image description here

2

It's easy to create your own formatter that overrides the link formatter. Although, now that I see there is a module for this (Link), you may want to use that one, as you can set it at the field level, rather than as a setting in the formatter. But I thought this might be useful to someone, who wants to build their own formatter for a link where you can add a class.

namespace Drupal\mymodule\Plugin\Field\FieldFormatter;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\link\LinkItemInterface;
use Drupal\link\Plugin\Field\FieldFormatter\LinkFormatter;

/**
 * Plugin implementation of the 'link' formatter.
 *
 * @FieldFormatter(
 *   id = "link_with_class",
 *   label = @Translation("Link with Custom Class"),
 *   field_types = {
 *     "link"
 *   }
 * )
 */
class LinkClassFormatter extends LinkFormatter {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return parent::defaultSettings() +
    ['class' => ''];

  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $elements = parent::settingsForm($form, $form_state);

    $elements['class'] = array(
      '#type' => 'textfield',
      '#title' => t('Class on Link'),
      '#default_value' => $this->getSetting('class'),
    );

    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {

    $summary = parent::settingsSummary();

    $settings = $this->getSettings();

    if (!empty($settings['class'])) {
      $summary[] = t('Class(es) on button = "@classes"', array('@classes' => $settings['class']));
    }

    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  protected function buildUrl(LinkItemInterface $item) {
    $url = parent::buildUrl($item);

    $settings = $this->getSettings();

    if (!empty($settings['class'])) {
      $options = $url->getOptions();
      $options['attributes']['class'] = $settings['class'];
      $url->setOptions($options);
    }

    return $url;
  }

}
1

Here is the simple solution -

function THEME_preprocess_file_link(&$variables)
{
  $variables['attributes']->addClass(array('your_custom_class'));
}
0

I'm still testing it out for any bugs, but placing this in your .theme file will add the field's name as a class for all fields. This is for Drupal 8.2:

function mytheme_preprocess_field(&$variables, $hook) {
  $variables['attributes']['class'][] = $variables['element']['#field_name'];
}

Seems like something every theme should include to make styling easier.

0

All the other solutions add classes to the field wrapper. This one adds a class to the <a> tag itself:

/*
 * Implements hook_preprocess__HOOK().
 */
function hook_preprocess_field(&$variables) {
  $classes = [
    'button',
    'blue'
  ];
  $variables['items'][0]['content']['#url']->setOption('attributes', ['class' => $classes]);
}

Your Answer

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

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