Adding helpful CSS classes to elements in Drupal 9 themes

Sarah Carney
4 min readAug 16, 2022

Hello! It’s been awhile since I’ve written something. I want to share a smattering of examples of adding classes to different elements in a Drupal 9 theme. Would love to hear what classes you’re adding and how.

  • Add a CSS class to body if the user is logged in.
  • Add a CSS class to the body if you are on the front page
  • Add a region name class to region template
  • Add node_id and node_type CSS classes to body
  • Add CSS classes for node Add, Edit, and Delete forms to body
  • Add view_id and view display_id CSS classes to body
  • Add your own CSS classes to Views buttons
  • Add your own CSS classes to local actions
  • Add your own CSS classes to Read More and Comments links
  • Add your own CSS class to the search form
  • Add your own CSS class to a field
  • Add your own CSS to multi-value fields
  • Add your own CSS class to form element descriptions
  • Using field values as CSS class names
  • Using theme settings as CSS classes in theme templates
  • Add block type as a CSS class in block templates

Things you should replace with your own info are in bold.

Add a CSS class to body if the user is logged in

The logged_in variable is available in theme templates.

In the html.html.twig template where body liv:

{% set body_classes = [ 
logged_in ? 'logged-in',
]
%}
<body{{ attributes.addClass(body_classes) }}>
...

Add a CSS class to the body if you are on the front page

In the html.html.twig template where body lives:

{% set body_classes = [ 
is_front ? 'is_front' : 'not_front',
]
%}
<body{{ attributes.addClass(body_classes) }}>
...

This also works in other templates like page.html.twig, block.html.twig, status-messages.html.twig, etc.

Add region CSS class to region template

region is built in!

In region.html.twig (or templates that would override it):

{% 
set region_classes = [
'region_' ~ region|clean_class,
]
%}
<div{{ attributes.addClass(region_classes) }}>

Add node-id and node-type CSS classes to body.

In the .theme file:

use Drupal\node\NodeInterface;function mytheme_preprocess_html(&$variables) {
$node = \Drupal::request()->attributes->get('node');
if ($node instanceof NodeInterface) {
$variables['attributes']['class'][] = 'node-id_' . $node->id();
}
if (isset($variables['node_type'])) {
$variables['attributes']['class'][] = 'node-type_' . $variables['node_type'];
}

Add CSS classes for node Add, Edit, and Delete forms to body

In .theme

function mytheme_preprocess(&$variables, $hook) {
$route_name = \Drupal::routeMatch()->getRouteName();

if ($route_name == 'entity.node.edit_form') {
$variables['is_node_edit'] = 'edit';
}
elseif ($route_name == 'node.add') {
$variables['is_node_add'] = 'add';
}
elseif ($route_name == 'entity.node.delete_form') {
$variables['is_node_delete'] = 'delete';
}
}

Then in html.html.twig

{%
set body_classes = [
is_node_edit == 'edit' ? 'node-form node-form_' ~ 'edit',
is_node_add == 'add' ? 'node-form node-form_' ~ 'add',
is_node_delete == 'delete' ? 'node-form node-form_' ~ 'delete',
]
%}

<body{{ attributes.addClass(body_classes) }}>

Add view_id and view display_id CSS classes to body

function mytheme_preprocess_html(&$variables) {
$route = \Drupal::routeMatch()->getRouteObject();
$view_id = $route->getDefault('view_id');
$display_id = $route->getDefault('display_id');
if ($view_id) {
$variables['attributes']['class'][] = 'view_' . $view_id;
$variables['attributes']['class'][] = 'view-display_' . $display_id;
}
}

Add your own CSS classes to Views buttons

function mytheme_preprocess_views_view(&$variables) {
$variables['more']['#options']['attributes']['class'] = array('my-button-class1', 'my-button-class2');
}

Add your own CSS classes to local actions

function mytheme_preprocess_menu_local_action(&$variables) {
$variables['link']['#options']['attributes']['class'][] = 'my-button-class1 my-button-class2';
}

Add your own CSS classes to Read More and Comments links

function mytheme_theme_preprocess_links(&$variables) {
if (!empty($variables['links']['node-readmore']['link'])) {
$variables['links']['node-readmore']['link']['#options']['attributes']['class'][] = 'my-button-class1 my-button-class2';
}

There are several buttons! Repeat the $variables line for each button type by replacing node-readmore with the button types below as needed:

  • comment-comments
  • comment-add
  • comment-delete
  • comment-edit
  • comment-reply
  • book_printer
  • book_add_child

Add your own CSS class to the search form

function mytheme_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
if( $form_id == 'search_block_form') {
$form['actions']['submit']['#attributes']['class'][] = 'my-search-class';
}
}

Add your own CSS class to a field

There may be other ways to do this, but here is one way.

function mytheme_preprocess_field(&$vars) {
if ($vars['element']['#field_name'] == 'field_people_image') {
foreach ($vars['items'] as $key => $item) {
$vars['items'][$key]['content']['#item_attributes']['class'][] = 'my-field-class';
}
}
}

Add your own CSS to multi-value fields

function mytheme_preprocess_field_multiple_value_form(&$variables) {
$variables['table']['#attributes']['class'][] = 'my-multi-value-class';
}

Add your own CSS class to form element descriptions

function mytheme_preprocess_form_element(&$variables) {
if ($variables['element']['#type'] == 'managed_file') {
$variables['description_display'] = 'before';
$variables['description']['attributes']['class'] = 'my-description-class';
}
}

You can replace managed_file with the form type as needed, such as select or textarea. Find a list of form element names here at the Drupal API documentation: form and render elements.

Using field values as CSS class names in Drupal 8/9

Using theme settings as CSS classes in theme templates

In this example I want to use them in my block templates.

function mytheme_preprocess_block(&$variables) {
$variables['my_variable_name'] = theme_get_setting('theme_setting_name');
}

Then in the template, for example:

{% set my_classes = [
my_variable_name|clean_class,
my-other-class,
]
%}
{# Then, for example #}
<div class="my_classes">
...
</div>
{# Or #}
<div{{ attributes.addClass(my_classes) }}>
...
</div>

More information and how to add your own theme settings at the official Drupal theming documentation. This same technique works perfectly well for both mytheme_preprocess_page and mytheme_preprocess_node.

Add block type as a CSS class in block templates

function mytheme_preprocess_block(&$variables) {
if ($variables['elements']['#base_plugin_id'] == 'block_content') {
$blockType = strtr($variables['content']['#block_content']->bundle(), '_', '-');
$variables['attributes']['class'][] = 'block-type_' . $blockType;
}
}

--

--