Replacements for classnames
classnames builds a className string from strings, objects and arrays. clsx takes the same arguments and is a smaller drop-in replacement.
clsx
clsx has no dependencies and ships both ESM and CommonJS builds. It accepts the same strings, objects, arrays and falsy values, so in most code only the import changes:
ts
import classNames from 'classnames'
import { clsx } from 'clsx'
const className = classNames('btn', { 'btn-active': isActive }, extra)
const className = clsx('btn', { 'btn-active': isActive }, extra) clsx also has a default export, so import clsx from 'clsx' works too.
If you only ever pass strings, clsx/lite is even smaller. It ignores objects and arrays, so clsx('btn', { active: true }) from clsx/lite returns 'btn'.
A few things work differently:
classnamescalls a customtoString()on objects that define one.clsxtreats every object as a map of class names, so an object with its owntoStringmethod becomes'toString'and a class instance with atoStringmethod becomes''. Convert such values withString(value)before passing them.classnames/dedupeandclassnames/bindhave noclsxequivalent. For CSS modules, look up the names yourself, for exampleclsx(styles.btn, isActive && styles.active).