classnames
August 5, 2023 • Eleventy
A couple of months ago I released version 0.2.0 of my classnames
plugin for Eleventy, a port of the popular package by JedWatson. I thought I’d talk a little bit about what it does, and why I find it so dang useful even in a non-React environment.
Conditional class names
I work with Nunjucks components in Eleventy a lot, both at work and in my personal projects. A very common need is to build class
attribute strings whose values are dependent upon some condition or other. For example:
- A component might have one or more variants, like
my-component--secondary
ormy-component--large
- It might also support scoping when nested inside another component — ex.,
my-component
might be scoped ashero__my-component
if that specific context necessitated an explicit, dedicated selector - We might want to support defining custom class names on the component verbatim to ensure the greatest amount of future flexibility
One way to approach this in Nunjucks is with inline conditional blocks. Here, we’re giving the component a my-component
class and setting my-component--<variant>
if the variant
variable is defined:
<div class="my-component {% if variant -%}my-component--{{ variant }}{%- endif %}">
This is just a single conditional class name, but I already find it hard to read. I also find it challenging to maintain,especially as a component’s class names grow and change over time.
I was working on a React project last year when my teammate Dan introduced me to classnames
, a package built specifically for building a single class
attribute string out of a variety of potentially truthy or non-truthy constituent strings.
I found this tremendously useful for building React components — so do a lot of people, I suspect; it’s currently coming in at 12 million weekly downloads 😮 — and started tinkering on a shortcode for Eleventy that I used in some personal projects. I eventually packaged it up as a proper Eleventy plugin and got it published on NPM.
Here’s the same component as above, using the classnames
shortcode instead of inline conditionals:
<div class="{% classnames
"my-component",
"my-component--" + variant if variant
%}">
This is much, much more legible, at least for my old eyes and brain wiring. It really starts to shine as class name composition becomes more complex:
<div class="{% classnames
"my-component",
"my-component--" + variant if variant,
scope + "__my-component" if scope,
className
%}">
Like the original classnames
package, the Eleventy plugin joins truthy strings and removes falsy ones:
---
variant: secondary
scope: hero
---
<div class="{% classnames
"my-component",
"my-component--" + variant if variant,
scope + "__my-component" if scope,
className
%}">
producing a nice, compact sequence of classes in the resulting HTML:
<div class="my-component my-component--secondary hero__my-component">
What I like
A lot of our preferences about how to write code come down to personal taste, and this may not be an exception, but I find this has some direct benefits — especially when working on a team:
- It’s easier to scan the rule set for an element’s classes on a line-by-line basis
- Diffs become more meaningful when each class name condition is defined on its own line
- As a result, PRs are easier and quicker to review
If you find yourself wrestling with unwieldy solutions to building class strings in Eleventy, give the classnames
plugin a whirl 💫