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.
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.
yield
and section
TagsNow 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.
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-article13{{ /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-title15 16 17 18short-title19 20 21">22 <h2>Nectar of the Gods</h2>23 24 25</div>26 27<div class="28 29 30long-title31 32 33 34the-magic-article35">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.
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-title10 {{ /if }}11 12 {{ if title | contains('magic') }}13 the-magic-article14 {{ /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>
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.
∎
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.