Creating Dynamic CSS Class Names with Statamic

May 29, 2022 —John Koster

In this article, we will look at one way to construct dynamic CSS class names when writing Antlers templates for a Statamic site. This technique will utilize the Antlers Runtime parser and the yield and section features.

#Setting up Our Collection Loop

We will create a simple template based on the data from the Cool Writings starter kit. Our simple template will contain the list of entries but will eventually have a dynamic list of classes based on many different conditions.

1{{ collection:articles }}
2 <div class="dynamic classes here">
3 <h2>{{ title }}</h2>
4 </div>
5{{ /collection:articles }}

If we were to render this template, we would see output similar to the following:

1<div class="dynamic classes here">
2 <h2>'Dance Like No One is Watching' Is Bad Advice</h2>
3</div>
4 
5<div class="dynamic classes here">
6 <h2>Nectar of the Gods</h2>
7</div>
8 
9<div class="dynamic classes here">
10 <h2>The Magic Happens at 7 1/2 Pumps</h2>
11</div>

This output is not very interesting, but we will work to change that throughout the rest of this article.

#Adding the yield and section Tags

Now that we have our collection loop, we can set things up to construct our dynamic CSS classes using the yield and section features.

The yield tag will let us define a named section of our template that we can set the contents of later. The section tag allows us to set the contents that should render. One thing to note with the Antlers Runtime parser is that yield and section are loop-aware and will help manage dynamic contents for each loop iteration.

Let's now update our collection loop to contain our yield and section placeholders:

1{{ collection:articles }}
2 <div class="{{ yield:article_class /}}">
3 <h2>{{ title }}</h2>
4 
5 {{ section:article_class }}{{ partial:entry_classes }}{{ /section:article_class }}
6 </div>
7{{ /collection:articles }}

On line 2, you will notice that we added the {{ yield:article_class /}} tag. This tag will let Antlers know that if we push content to a section named article_class, it should appear in this part of the template (the self-closing tag is personal preference). Line 5 is where things start to get interesting.

When we call the section tag, we must specify what section we want to set the contents of as the method name. The content of the section tag pair is what will be rendered by the {{ yield:article_class /}} tag. To keep our loop clean and well organized, we will place our conditional logic in a partial template.

#Creating the Conditional Logic

We will use an Antlers partial to contain the conditional logic that will output our dynamic CSS classes to help keep our template organized and clean.

Inside entry_classes.antlers.html:

1{{ if title == 'Nectar of the Gods' }}
2 nectar-title
3{{ /if }}
4 
5{{ if title | length > 18 }}
6 long-title
7{{ else }}
8 short-title
9{{ /if }}
10 
11{{ if title | contains('magic') }}
12 the-magic-article
13{{ /if }}

Our partial now contains several conditional statements and outputs the CSS classes that will apply under those conditions. Rendering our template would now produce output similar to the following:

1<div class="
2 
3 
4long-title
5 
6 
7">
8 <h2>'Dance Like No One is Watching' Is Bad Advice</h2>
9 
10 
11</div>
12 
13<div class="
14nectar-title
15 
16 
17 
18short-title
19 
20 
21">
22 <h2>Nectar of the Gods</h2>
23 
24 
25</div>
26 
27<div class="
28 
29 
30long-title
31 
32 
33 
34the-magic-article
35">
36 <h2>The Magic Happens at 7 1/2 Pumps</h2>
37 
38 
39</div>

We are getting closer, but that whitespace within the class attribute feels obnoxious. We will take care of that next.

#Cleaning up the Class List Whitespace

At first, we may attempt to do something like this:

1{{ {yield:article_class} | collapse_whitespace }}

Using modifiers on the yield tag will not work. Because of how yield and section internally work, yield tag results cannot be used like a variable (the Antlers rendering process is no longer available when section contents are rendered).

Instead of using modifiers, we will create a custom tag that will help us get our whitespace under control. Create a new file at app/Tags/CollapseWhitespace.php with the following contents:

1<?php
2 
3namespace App\Tags;
4 
5use Statamic\Tags\Tags;
6use Stringy\StaticStringy;
7 
8class CollapseWhitespace extends Tags
9{
10 
11 public function index()
12 {
13 return StaticStringy::collapseWhitespace($this->parse());
14 }
15}

This custom tag implementation will effectively do the same thing as the collapse_whitespace modifier to the tag's contents.

We can now update our entry_classes.antlers.html partial to contain our new tag:

1{{ collapse_whitespace }}
2 {{ if title == 'Nectar of the Gods' }}
3 nectar-title
4 {{ /if }}
5 
6 {{ if title | length > 18 }}
7 long-title
8 {{ else }}
9 short-title
10 {{ /if }}
11 
12 {{ if title | contains('magic') }}
13 the-magic-article
14 {{ /if }}
15{{ /collapse_whitespace }}

Rendering our template now produces results similar to the following output:

1<div class="long-title">
2 <h2>'Dance Like No One is Watching' Is Bad Advice</h2>
3</div>
4 
5<div class="nectar-title short-title">
6 <h2>Nectar of the Gods</h2>
7</div>
8 
9<div class="long-title the-magic-article">
10 <h2>The Magic Happens at 7 1/2 Pumps</h2>
11</div>

#Considerations for CSS Libraries and Build Tools

Some CSS libraries and build tools may analyze your templates to reduce the final size of your compiled CSS files. When using these types of libraries and build tools, you should consult their documentation to learn how to add your dynamic CSS classes to a safe list to be included in the final CSS files. Some CSS libraries and build tools may analyze your templates to reduce the final size of your compiled CSS files. When using these types of libraries and build tools, you should consult their documentation to learn how to add your dynamic CSS classes to a safe list to include them in the final CSS files.

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.