Conditional CSS Class Utility
The `classnames` utility simplifies the conditional joining of CSS class names in JavaScript and TypeScript applications. It accepts any number of arguments, including strings, objects (where keys are class names and values are booleans), and arrays, intelligently combining them into a single, space-separated string. The package is currently at version 2.5.1, following the SemVer standard, indicating a strong commitment to stability and backwards compatibility for minor and patch releases. It is widely adopted, especially within the React ecosystem, due to its robust performance and minimalist API. Its key differentiators include its extreme stability, thorough test suite, and focus on performance, ensuring it reliably handles class name generation in high-frequency scenarios across browsers and Node.js environments. The project's philosophy emphasizes speed and stability, with updates thoroughly reviewed for performance implications.
Common errors
-
TypeError: classNames is not a function
cause Attempting to use `classNames` after an incorrect ES module import (e.g., `import { classNames } from 'classnames';` instead of `import classNames from 'classnames';`). This happens because `classnames` exports a default function, not a named one.fixChange your import statement to `import classNames from 'classnames';` for ES modules. If using CommonJS, ensure you are using `const classNames = require('classnames');`. -
ERR_REQUIRE_ESM (or similar module resolution errors in Node.js ESM projects)
cause In a Node.js project configured as an ES module (`"type": "module"` in `package.json`), trying to `require('classnames')` might fail if Node.js resolves `classnames` as an ES module due to its `exports` field. This is a common interoperability issue.fixPrefer `import classNames from 'classnames';` in ES module contexts. If you *must* use `require` in an ESM file (e.g., for conditional loading), consider Node.js's `createRequire` utility: `import { createRequire } from 'module'; const require = createRequire(import.meta.url); const classNames = require('classnames');`. -
Class names being returned as `[object Object]` as of v2.3.0
cause This issue could arise in specific bundling scenarios (e.g., Rollup/Babel) when `classnames` introduced support for custom `toString()` methods on arguments in v2.3.0, potentially leading to objects not being stringified as expected.fixReview your bundler configuration and ensure proper handling of objects passed to `classnames`. If you encounter this, consider simplifying the arguments passed or upgrading your bundling tools. This issue was largely addressed in subsequent patch releases. Ensure `classnames` is at least v2.3.2.
Warnings
- breaking Version 2.0.0 introduced ES6 module export. While existing CommonJS `require` statements continued to work, modern ESM `import` syntax changed how `classnames` should be imported. Incorrect import patterns (e.g., named imports for a default export) can lead to runtime errors.
- gotcha Prior to v2.5.0, module resolution for hybrid CJS/ESM projects, especially in Node.js environments with `"type": "module"` set, could be inconsistent. Version 2.5.0 added the `exports` field to `package.json` to improve module interoperability.
- deprecated The `component-classes` dependency was removed in v2.0.0, streamlining the package. While not a direct breaking change for users, it signifies a move towards a leaner, dependency-free utility.
- gotcha There is an alternate `dedupe` version of `classNames` available that offers more robust deduplication for complex scenarios but is significantly slower (up to 10x slower). It is offered as an opt-in for specific use cases.
Install
-
npm install classnames -
yarn add classnames -
pnpm add classnames
Imports
- classNames
import { classNames } from 'classnames';import classNames from 'classnames';
- classNames
const classNames = require('classnames'); - classNames
if (window.classNames) { /* use window.classNames */ }
Quickstart
import classNames from 'classnames';
const isActive = true;
const hasError = false;
const theme = 'dark';
// Basic usage with strings
const classes1 = classNames('container', 'header');
console.log(classes1); // Expected: 'container header'
// Conditional classes using objects
const classes2 = classNames('button', {
'button--primary': isActive,
'button--danger': hasError,
[`theme-${theme}`]: true // Dynamic class name based on variable
});
console.log(classes2); // Expected: 'button button--primary theme-dark'
// Mixing strings, objects, and arrays
const classes3 = classNames(
'card',
{ 'card--active': isActive },
['shadow', 'rounded'],
null,
undefined,
{ 'card--hidden': !isActive }
);
console.log(classes3); // Expected: 'card card--active shadow rounded'