How do I Add Custom Classes to the HTML Body in Drupal using Twig?

As a designer, you want to give some variation to your designs not only for aesthetic looks but also because your content will always have variations. There are lots of ways to set up content in Drupal from using basic content types and blocks to using references fields and views or paragraphs.

At some stage, however, you may want to use a field to allow the content creator to choose a style setting and then add the setting to the body element so that it can be used to style the full page. This article is going to show you how you can add a class to the body tag, first by hardcoding a value and then by passing a value from a content type field and then finally a paragraph entity field that is referenced to a content type. Let's get started!

The first you will need to do is add an MY_THEME_NAME.theme file to the root of your theme. In this example, I will be using my Kodomo theme so the file will be named kodomo.theme. This file is a PHP file so you will need to add the <?php opening tags to it. In this .theme file, we will add what are called hook preprocess functions. They are called hook functions as they hook into the theme build and add the code. Let's start with a basic example and use the HTML preprocess function.

Add a class using attributes in Drupal HTML preprocess function

In the below code you can see that we set a new class called kodomo by adding it to the attributes class array variables. This will automatically add it to the body class attribute in the HTML. As such, this is probably not that useful but it is always good to start with a simple example.

/**
 * Implements hook_preprocess_HOOK() for HTML document templates.
 */
function kodomo_preprocess_html(&$variables)
{
  $variables['attributes']['class'][] = 'kodomo';
}

Adding a class using a custom variable n Drupal

In this next example, we add a custom variable called theme_style and assign new-style to it. This is also done in the HTML preprocess hook.

function kodomo_preprocess_html(&$variables)
{
  $variables['theme_style'] = 'new-style';
}

Now we have a new variable we can add the variable to the body_classes in the twig template. As you would expect new-style will be added to the body class attribute.

{%
  set body_classes = [
    logged_in ? 'user-logged-in',
    not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
    node_type ? 'page-node-type-' ~ node_type|clean_class,
    db_offline ? 'db-offline',
    theme_style
  ]
%}

The above example, also probably isn't that useful as it will be added to all pages that the block is added to. i.e if you add the variable to body_classes it will be added to all pages.

Using static variables to save and retrieve variables

Please note even though this method works now the drupal_static() function will be deprecated in a future release. This doesn't look like it will be in the very near future but it worth knowing that it will deprecated. Please check [PP-1] Deprecate drupal_static() and drupal_static_reset().

I will look at other methods to do this myself and when I have a new solution I will add it here. That said we can still use this design pattern and in doing so we can still learn something so let's continue.

To use the Drupal static function create a function block like below and add it to the .theme file. I like to add it to the top. Hopefully, the code is self-explanatory but we will use the $var_name & $new_value to set the body class from a field on a content type.

/* Static Function */
function _myTheme_var( $var_name, $new_val = NULL)
{

  $vars = &drupal_static(__FUNCTION__, array());

  // If a new value has been passed
  if ($new_val) {
    $vars[$var_name] = $new_val;
  }

  return isset($vars[$var_name]) ? $vars[$var_name] : NULL;
}

Adding a class set from using a content type field select list value

If you are unfamiliar with all the templates in a Drupal theme make sure you understand that by reading Part 2 of Drupal theme building

What we will do is use a field value from a node. This code will be in a node preproces hook,  MY_THEME_proprocess_node(), and will use the static function to set a new value to the variable name.

use Drupal\node\Entity\Node;

function kodomo_preprocess_node(&$variables)
{
  $node = $variables['node'];

/* Using node field value to set a variable */
  $theme_style_value = $node->field_style->value;
  // print_r($node->field_style->value);

/* Set my_var to the  $theme_style_value variable   */
  $variables['theme_style'] = _myTheme_var('my_var', $theme_style_value);
}

Use the var set in the node preprocess function by retrieving it using the static function and setting a the new variable as we did in the second example at the start.

/**
 * Implements hook_preprocess_HOOK() for HTML document templates.
 */
function kodomo_preprocess_html(&$variables)
{
-  $variables['theme_style'] = 'new-style';
+  $variables['theme_style'] = _myTheme_var('my_var');
}

That's it now you can provide a select list of options for different styles to add variations dependent on the content.

To use a value from a reference field such as a paragraphs field please check the bonus below.

Bonus: using a variable from a paragraph select list field

Thanks for reading be sure to sign up for the newsletter to get more Drupal themeing tips and tricks. Not only do I write about Drupal I also write about design and front-end development.

Tags