DEV Community

Cover image for You do not need to use the classnames package
Nick Taylor (he/him)
Nick Taylor (he/him)

Posted on • Originally published at iamdeveloper.com on

You do not need to use the classnames package

Do not get me wrong, the classnames package is really handy. It is also quite popular with just over 3.5 million downloads per week as of the date of this blog post. Most React based projects I have worked on use it.

If you are not familiar with the classnames package, it allows you to build a set of CSS classes based on some conditionals. Straight from there documentation:

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
Enter fullscreen mode Exit fullscreen mode

Note: true and false are used to simplify the example, but normally these would be conditional variables, methods or functions.

Having said that, JavaScript has come a long way and there are features in the language that allow us to do pretty much the same thing, specifically template strings or as it is also called, template literals.

If you are not familiar with template strings, you can build a string with variables mixed in. Let us look at the previous examples, but this time with template strings.

`foo bar` // => 'foo bar', not that exciting
`foo ${ true ? 'bar': '' }`; // => 'foo bar'
`${true ? 'foo-bar': '' }`; // => 'foo-bar'
`${ false ? 'foo-bar' : ''}` // => ''
`${ true? 'foo': '' }, { true ? 'bar': '' }`; // => 'foo bar'
`${ true ? 'foo' : ''} ${ true? 'bar' : '' }`; // => 'foo bar'
Enter fullscreen mode Exit fullscreen mode

These are trivial examples, but it is just to show you that you can do pretty much the same thing with template literals. If you want to see this in action, here is an example from my site's source:

GitHub logo nickytonline / iamdeveloper.com

Source code for my web site iamdeveloper.com

Netlify Status

Welcome

This is the source code for the web site of Nick Taylor built using the Eleventy static site generator. It uses Andy Bell's Hylia template. I've made tweaks to it and will probably make more over time, but just wanted to give Andy a shout out for his awesome template.

Terminal commands

Install the dependencies first

npm install
Enter fullscreen mode Exit fullscreen mode

Serve the site locally in watch mode

npm start
Enter fullscreen mode Exit fullscreen mode

Build a production version of the site

npm run production
Enter fullscreen mode Exit fullscreen mode

Test the production site locally

cd dist
npx serve
Enter fullscreen mode Exit fullscreen mode
...
<nav
   className={`navbar is-transparent ${styles.navbar}`}
   role="navigation"
   aria-label="main-navigation"
   data-cy="nav-bar"
>
...
Enter fullscreen mode Exit fullscreen mode

https://github.com/nickytonline/www.iamdeveloper.com/blob/master/src/components/Navbar.tsx#L51

This is not mind blowing code, but just another way to do it.

Happy coding!

Photo by David Rotimi on Unsplash

Discussion (6)

Collapse
pallymore profile image
Yurui Zhang
`${ false ? '' : 'foo-bar'}` // => ''
Enter fullscreen mode Exit fullscreen mode

this should return 'foo-bar' instead of ''.

For simple use cases classnames is definitely an overkill, but I would say if you have more than 2 conditions in the same template literal it becomes ugly really quickly.

Also there is a smaller package for the same purpose called clsx.

Collapse
nickytonline profile image
Nick Taylor (he/him) Author • Edited on

Thanks, correction made. Yes, agreed that it could get unwieldy, just showing another way of doing things is all. 😉

Collapse
lesbaa profile image
Les • Edited on

Agreed, I think classNames is a bit of overkill for what is essentially concatenation of strings. However template literals can get hectic and hard to reason about very quickly. What I normally do is:

const componentClassName = [
  'some-base-class',
  someBooleanCondition && 'a-class-in-here',
  someOtherBoolean && 'another-class',
]
  .filter(Boolean)
  .join(' ')

Enter fullscreen mode Exit fullscreen mode

Written on a mobile so forgive any typos!

Collapse
tomekbuszewski profile image
Tomek Buszewski

I remember ditching classnames long ago. At some point we've decided that vendor for joining strings is an overkill. I think we've used something like this (pseudocode):

const cls = (input: string|boolean[]): string => input.filter((cond: string | boolean) => typeof cond === "string").join(", ");

<div className={cls(["one", isTrue ? "two" : "three", isAnything && "four"]) />
Enter fullscreen mode Exit fullscreen mode

And it worked perfectly. You could drop the filter element, but then you'll get false as one of the classes from time to time.

Collapse
gnsp profile image
Ganesh Prasad

I had written a very similar blogpost about 2 years ago. Eventually after using template literals in major projects, (some of them currently in production on zomato), I found a number of pitfalls and redundancies with this approach. This led me to developing a safer and easier-to-use template literals based classNames alternative called classd. Recently I wrote a blogpost on opensourcing classd describing the usecases. classd also provides a classNames like function (classdFn) which is intended to be a drop-in replacement for classNames. It supports more types than POJOs (like maps, sets and iterables) and in majority of cases it's more performant than classNames. Do give it a try if you are interested in using template literals for composing classes.

Collapse
simkessy profile image
simkessy

I've been using template strings to build classes for a while and every time I come up against an existing project which uses classNames I scratch my head trying to understand why this exist. Thanks for validating this view.