If you’ve done much work in JavaScript, you’ve likely had to build up a string of CSS classes to apply to an element.

If you know all of the classes when you’re writing the code, you can just write them:

Known Classes Up Front
const knownClasses = "grid-block vertical shrink"

But what if you don’t know all of the classes up front because you have to merge in caller-supplied classes? With ES2015, you can use string interpolation:

String Interpolated Classes
const interpolatedClasses = `my-class ${callerClass}`

This works, unless the caller doesn’t supply a class. Suddenly, you’ve got elements with a class of undefined.

Or what if you have to conditionally include a class based on some condition? Things can get out of hand in a hurry.

Conditional Classes
let conditionalClasses = "btn"
if (isPressed()) classes += " btn-pressed"
else if (isHovered()) classes += " btn-over"

Enter Jed Watson’s classnames library.

classnames handles all of these cases:

Using classnames
import classNames from "classnames"
const knownClasses = classNames("grid-block", "vertical", "shrink")
const interpolatedClasses = classNames("my-class", callerClass)
const conditionalClasses = classNames("btn", {
"btn-pressed": isPressed(),
"btn-over": isHovered()
})

classnames takes a list of classes, arrays, or objects. It flattens the arrays and ignores any falsy classes. For objects, it treats each property of the object as a class and only includes the ones whose values are truthy.

This makes for a really clear specification of what classes will be used and eliminates the undefined class I mentioned above.

What about dynamic classes, such as when using CSS modules?

There is a bind version that you can use, but I prefer to use ES2015 computed property syntax instead:

Computed Classes
import styles from './styles'
const classes = classNames(styles.button, {
[styles.pressed]: isPressed(),
[styles.over]: isHovered()
})

All in all, classnames is a really useful part of my toolkit and has quickly become one of my favorite libraries.