Drupal 8 Theming: How to Set Custom HTML Classes in a Block Region
Now that I'm digging into Drupal 8 theming and its awesomeness, I'm discovering some really useful methods and functions. At the same time, I'm learning a lot and having fun.
In this post I'll show you how you can set a custom HTML class within a block region. I'll be doing this in a sub-theme that uses Drupal 8's Classy as a base-theme.
Our use case is that there are three "preface" block regions defined in a Classy sub-theme, "First", "Second", and "Third." When these regions render as HTML, Classy gives them one common class called region
. We'd like to have something more specific such as region--preface
that can be used as a class for theming any of these preface regions.
Getting started, examine the array
The first thing to do is enable Devel Kint to examine the block region array. Kint is part of the Devel module and you can either download it from drupal.org or use Drush. Right now, Devel for Drupal 8 is available as a dev release; using drush we can download and enable it using these commands.
drush dl devel-8.x-1.x-dev -y
drush en kint -y
Next, I'll add a template_preprocess_region
in my sub-theme's .theme
file and kint()
the vars to see what's going on. In some cases, using kint right in a Twig template works well but in this case, you'll get much more info by using it as we do below in our .theme
file.
function mysubtheme_preprocess_region(&$vars) {
kint($vars);
}
Once I do this, I run a drush cr
and reload the page that has one of my preface regions on it. Here I see the array path to the region name and it's elements > #region.
So now in our preprocess region I can define that array path.
function mysubtheme_preprocess_region(&$vars) {
$region = $vars['elements']['#region'];
}
Note, you can also look in core's theme.inc
file to see how the region variables are defined and when I do that, I see something pretty similar to the above:
$variables['region'] = $variables['elements']['#region'];
The next thing I am going to do is create an array of my three preface regions that have already been defined in the theme:
$region_preface = array (
'preface_first',
'preface_second',
'preface_third',
);
Now that I define the array, I will set a common class for these three regions:
if (in_array($region, $region_preface)) {
$vars['attributes']['class'][] = 'region--preface';
}
Putting it all together
function mysubtheme_preprocess_region(&$vars) {
$region = $vars['elements']['#region'];
$region_preface = array (
'preface_first',
'preface_second',
'preface_third',
);
if (in_array($region, $region_preface)) {
$vars['attributes']['class'][] = 'region--preface';
}
}
Alternate Method using Twig set classes = []
One other way to set a custom class is to use the new set classes = []
method in a Twig template. So instead of setting the class in the .theme file, we'll create a variable for use in Twig.
if (in_array($region, $region_preface)) {
$vars['region_preface'] = 'region--preface';
}
To make use of this variable, I've already gone ahead and copied Classy's region.html.twig
into my sub-theme's template folder. I generally keep the same template folder structure in my sub-theme that classy gives you which looks something like this:
|\_**\_templates
| |\_\_**block
| |\_**\_content
| |\_\_**content-edit
| |\_**\_dataset
| |\_\_**field
| |\_**\_form
| |\_\_**layout
| |\_**\_misc
| |\_\_**navigation
| |\_**\_user
| |\_\_**views
Now in my region.html.twig
, I look for this existing code:
{%
set classes = [
'region',
'region-' ~ region|clean_class,
]
%}
Now we add the variable, region_preface
, that we created in our preprocess function.
{%
set classes = [
'region',
'region-' ~ region|clean_class,
region_preface|clean_class,
]
%}
Of note above is clean_class
which "prepares a string for use as a valid HTML class name." In other words, it removes invalid characters from our HTML classes so they render in a nice manner. We don't really need it here but it's nice to have and get used to using.
With either method above, be sure to run a drush cr
and reload your page. The HTML output should look something like this.
<div class="region region-preface-first region--preface"></div>
Now we can utilize the new common class region--preface
for theming all preface regions with common attributes.
Summary
The above tutorial starts to give us a little insight into Drupal 8 theming. As with all things Drupal, there are often several ways to do the same task so by no means are the methods above definitive. In a future post, I'll expand on this a bit and add a class based on a variable value.
Resources
- Filters - Modifying Variables In Twig Templates
- CSS architecture (for Drupal 8)
- Twig best practices - preprocess functions and templates
- Drupal 8 Theming: How I got Inspired by Drupal All Over Again