A simple javascript utility for conditionally joining classNames together

Last update: Jun 24, 2022

Classnames

NPM version Build status NPM Weekly Downloads License Supported by Thinkmill

A simple JavaScript utility for conditionally joining classNames together.

Install with npm, Bower, or Yarn:

# via npm
npm install classnames

# via Bower
bower install classnames

# or Yarn (note that it will automatically save the package to your `dependencies` in `package.json`)
yarn add classnames

Use with Node.js, Browserify, or webpack:

var classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'

Alternatively, you can simply include index.js on your page with a standalone <script> tag and it will export a global classNames method, or define the module if you are using RequireJS.

Project philosophy

We take the stability and performance of this package seriously, because it is run millions of times a day in browsers all around the world. Updates are thoroughly reviewed for performance impacts before being released, and we have a comprehensive test suite.

Classnames follows the SemVer standard for versioning.

There is also a Changelog.

Usage

The classNames function takes any number of arguments which can be a string or object. The argument 'foo' is short for { foo: true }. If the value associated with a given key is falsy, that key won't be included in the output.

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'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

Arrays will be recursively flattened as per the rules above:

var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

Dynamic class names with ES2015

If you're in an environment that supports computed keys (available in ES2015 and Babel) you can use dynamic class names:

let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });

Usage with React.js

This package is the official replacement for classSet, which was originally shipped in the React.js Addons bundle.

One of its primary use cases is to make dynamic and conditional className props simpler to work with (especially more so than conditional string manipulation). So where you may have the following code to generate a className prop for a <button> in React:

class Button extends React.Component {
  // ...
  render () {
    var btnClass = 'btn';
    if (this.state.isPressed) btnClass += ' btn-pressed';
    else if (this.state.isHovered) btnClass += ' btn-over';
    return <button className={btnClass}>{this.props.label}</button>;
  }
}

You can express the conditional classes more simply as an object:

var classNames = require('classnames');

class Button extends React.Component {
  // ...
  render () {
    var btnClass = classNames({
      btn: true,
      'btn-pressed': this.state.isPressed,
      'btn-over': !this.state.isPressed && this.state.isHovered
    });
    return <button className={btnClass}>{this.props.label}</button>;
  }
}

Because you can mix together object, array and string arguments, supporting optional className props is also simpler as only truthy arguments get included in the result:

var btnClass = classNames('btn', this.props.className, {
  'btn-pressed': this.state.isPressed,
  'btn-over': !this.state.isPressed && this.state.isHovered
});

Alternate dedupe version

There is an alternate version of classNames available which correctly dedupes classes and ensures that falsy classes specified in later arguments are excluded from the result set.

This version is slower (about 5x) so it is offered as an opt-in.

To use the dedupe version with Node.js, Browserify, or webpack:

var classNames = require('classnames/dedupe');

classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'

For standalone (global / AMD) use, include dedupe.js in a <script> tag on your page.

Alternate bind version (for css-modules)

If you are using css-modules, or a similar approach to abstract class "names" and the real className values that are actually output to the DOM, you may want to use the bind variant.

Note that in ES2015 environments, it may be better to use the "dynamic class names" approach documented above.

var classNames = require('classnames/bind');

var styles = {
  foo: 'abc',
  bar: 'def',
  baz: 'xyz'
};

var cx = classNames.bind(styles);

var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz"

Real-world example:

/* components/submit-button.js */
import { Component } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';

let cx = classNames.bind(styles);

export default class SubmitButton extends Component {
  render () {
    let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';
    let className = cx({
      base: true,
      inProgress: this.props.store.submissionInProgress,
      error: this.props.store.errorOccurred,
      disabled: this.props.form.valid,
    });
    return <button className={className}>{text}</button>;
  }
};

Polyfills needed to support older browsers

classNames >=2.0.0

Array.isArray: see MDN for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill.

License

MIT. Copyright (c) 2018 Jed Watson.

GitHub

https://github.com/JedWatson/classnames
Comments
  • 1. Ability to handle object with own `.toString()` method

    This will allow using custom .toString() methods for objects to generate class names.

    From a performance standpoint, it's not affecting existing scenarios (scenario with an object containing .toString() method will be obviously slower a bit because we need to call this function).

    Here is JSPerf for this: https://jsperf.com/classnames-benchmark-for-tostring From JSPerf I can see that it's hard to find any performance impact, so I it's less than a statistical error rate. Time to time you can get results like this: 2018-07-19-145124_974x309_escrotum

    Closing #153 and same problem for SemanticUI https://github.com/Semantic-Org/Semantic-UI-React/issues/2599

    @dcousens , @JedWatson can you take a look?

    Reviewed by resetko at 2018-07-19 12:51
  • 2. Update the package using the clsx implementation?

    clsx by @clsx provides an interesting improvement over the actual classnames package implementation, it's faster and lighter. He has done an awesome job!

    However, given how popular classnames is and the relatively small performance improvement of clsx compare to the other dependency we are dealing with (often ~10 kB gzipped & ~10k ops/s). I have some doubt about the advantage of migrating from classnames to clsx: https://github.com/mui-org/material-ui/pull/14152. It's very likely that people will see classnames and clsx in their bundle, resulting in a negative outcome.

    @JedWatson Do you have any plan updating this package implementation using clsx as inspiration? I think that it's a path that would really benefit the React community. Thank you.

    Reviewed by oliviertassinari at 2019-01-11 19:32
  • 3. use [].join over concatenation

    A rebase of #36.

    Using node v4.1.1:

    * local#strings x 6,045,951 ops/sec ±1.58% (97 runs sampled)
    *   npm#strings x 3,216,399 ops/sec ±4.18% (88 runs sampled)
    
    > Fastest is local#strings
    
    * local#object x 2,542,831 ops/sec ±1.06% (98 runs sampled)
    *   npm#object x 2,526,207 ops/sec ±1.12% (91 runs sampled)
    
    > Fastest is local#object |   npm#object
    
    * local#mix x 948,129 ops/sec ±1.53% (93 runs sampled)
    *   npm#mix x 1,265,072 ops/sec ±0.97% (96 runs sampled)
    
    > Fastest is npm#mix
    
    * local#arrays x 623,087 ops/sec ±0.69% (98 runs sampled)
    *   npm#arrays x 814,812 ops/sec ±0.69% (103 runs sampled)
    
    > Fastest is npm#arrays
    

    Performance TL;DR:

    • pure string case is 180% faster
    • objects are the same
    • (string, object), arrays and multiple objects (mix) are all 25% slower

    Its a trade off, I'd wager the two most important cases are the pure string and (string, object) cases, in which case I'm still not sure what the decision should be.

    Perhaps some results from other engines could be the deciding factor? @impinball

    Reviewed by dcousens at 2015-09-30 00:02
  • 4. Use Array.isArray to check for array

    Array.isArray is faster than checking using Object.prototype.toString and is supported in modern browsers. React requires es5-shim.js (which includes Array.isArray) to support IE8. I modified the tests from #16 for benchmarks; pretty decent improvements shown.

    http://jsperf.com/classnames-util/5

    Reviewed by stuartsan at 2015-04-04 05:27
  • 5. Importing classnames installed via NPM while using Webpack

    Hi, firstly i'd like to thank you and the comunity for this amazing module, it certainly makes the life of anyone coding in React easier.

    It seems i'm doing something wrong, yet i cant find what it is. You see, i'm coding in React with Typescript, therefore, i use import * as ClassNames from "classnames" to import your module into my code, but webpack seems unable to include it in the output bundle, forcing me to include it as a separate asset in my html. While this isn't terribly annoying, it would be wonderfull if classnames could be bunbled with the rest of my code.

    I hope you can help me, either by telling what i'm doing wrong or by showing me how to hack around this. Thanks in advanced!!

    Reviewed by ramarivera at 2017-01-30 10:22
  • 6. Take array as argument?

    Readme clearly explains how to use an array ("if you have an array of these, use apply"). But I wonder if there's any reason not to also accept an array as a regular argument. Would you be open to a PR enabling that?

    Reviewed by davidtheclark at 2015-02-25 17:46
  • 7. add typescript contributor copyright notice

    @adidahiya @JKillian @seansfkelley @mradamczyk @marvinhagemeister @ccapndave this should be enough?

    As follow up to https://github.com/JedWatson/classnames/pull/103 (ref https://github.com/JedWatson/classnames/pull/103#issuecomment-426866682)

    IANAL, but, I think this is ok. Pinged the authors anyway...

    • [x] @adidahiya
    • [x] @JKillian
    • [x] @seansfkelley
    • [x] @mradamczyk
    • [x] @marvinhagemeister
    • [ ] @ccapndave
    • [x] @bradleyayers
    • [x] @cwmacdon
    Reviewed by dcousens at 2018-10-04 03:00
  • 8. Allow replacing of previous class names

    My use case is something like classNames('foo', { foo: false, bar: true }) should render out class="bar" instead of class="foo bar". Should this be supported by the library or is this out of scope? I'd be glad to submit a PR if this use case is something you guys plan to support.

    Reviewed by longlho at 2015-03-23 18:23
  • 9. speedup

    Strings concatenation is slow, here is simple speedup

    * local#strings x 6,304,350 ops/sec ±0.72% (95 runs sampled)
    *   npm#strings x 3,577,208 ops/sec ±1.38% (93 runs sampled)
    

    iojs v2.0.1

    Reviewed by silentroach at 2015-05-12 10:35
  • 10. Return of empty string results in class=""

    I can wrap this function in a comparison function and make className undefined myself, but was wondering if this was the best way. I'd looked through the issues and was surprised no one has raised this issue before.

    In the real world, I'd probably wrap this library in a library level utility that does this and not repeat the object twice. This is of course specific to React which sees an empty string and undefined differently.

    className={classNames({
    				'slds-is-today': isToday,
    				'slds-disabled-text': !isCurrentMonth,
    				'slds-is-selected': isSelectedDay
    			}) === '' ? undefined : classNames({
    				'slds-is-today': isToday,
    				'slds-disabled-text': !isCurrentMonth,
    				'slds-is-selected': isSelectedDay
    			})
    
    Reviewed by interactivellama at 2017-03-03 17:51
  • 11. Convert to ESM only

    On 2021-04-30, 25 days from now, NodeJS 10 will reach end of life. From that point all NodeJS environments will support ESM. Of course module bundlers already support this.

    There are two older pull requests to achieve this. Both are trying to keep backwards compatibility

    • #150
    • #194

    I think it’s time to drop support for alternative module systems and bower, meaning no new devdependencies are needed.

    Bower users can depend on specific git tags. It the master branch should keep working for Bower users, perhaps a new main branch should be created for further development, so the master branch can stay untouched indefinitely.

    I expect this to get some backlash at first from people who don’t like breaking changes, but this is what major releases are for in semver.

    Reviewed by remcohaszing at 2021-04-05 15:14
  • 12. Question about Dynamic class names with Tailwind CSS

    According to the Tailwind CSS doc:

    As outlined in [Class detection in-depth](https://tailwindcss.com/docs/content-configuration#class-detection-in-depth), 
    Tailwind doesn’t actually run your source code and won’t detect dynamically constructed class names.
    
    Don't construct class names dynamically
    <div class="text-{{ error ? 'red' : 'green' }}-600"></div>
    
    Always use complete class names
    <div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
    

    Do you recommend using classnames with Tailwind CSS?

    let buttonType = 'blue';
    classNames({ [`text-${buttonType}-500`]: true });
    
    Reviewed by shinokada at 2022-05-16 22:12
  • 13. Audit vulnerabilities detected in the classnames project on Tag: v2.3.1

    Issue: We detected vulnerable dependencies in your project by using the command “npm audit”:

    npm audit report

    lodash <4.17.21 Severity: high Command Injection - https://npmjs.com/advisories/1673 fix available via npm audit fix node_modules/lodash

    1 high severity vulnerability

    To address all issues, run: npm audit fix

    Questions: We are conducting a research study on vulnerable dependencies in open-source JS projects. We are curious:

    1. Will you fix the vulnerabilities mentioned above? (Yes/No), and why?:
    2. Do you have any additional comments? (If so, please write it down):

    For any publication or research report based on this study, we will share all responses from developers in an anonymous way. Both your projects and personal information will be kept confidential.

    Description: Many popular NPM packages have been found vulnerable and may carry significant risks [1]. Developers are recommended to monitor and avoid the vulnerable versions of the library. The vulnerabilities have been identified and reported by other developers, and their descriptions are available in the npm registry [2].

    Steps to reproduce:

    • Go to the root folder of the project where the package.json file located
    • Execute “npm audit”
    • Look at the list of vulnerabilities reported

    Suggested Solution: Npm has introduced the “npm audit fix” command to fix the vulnerabilities. Execute the command to apply remediation to the dependency tree.

    References: 2019. 10 npm Security Best Practices. https://snyk.io/blog/ten-npm-security-best-practices/. 2021. npm-audit. https://docs.npmjs.com/cli/v7/commands/npm-audit.

    Reviewed by mahirkabir at 2021-09-30 12:02
  • 14. Typescript: Throws an error when we pass spread operator of undefined

    Code snippet:

    import classNames from "classnames";
    const styles = undefined;
    
    console.log(classNames(["ui-component", ...styles]))
    

    Error:

    Cannot read property 'length' of undefined
    

    shall we add a type check to prevent this ?.

    Reviewed by pajaydev at 2021-09-07 07:18
  • 15. access bind object

    const styles = {
      base: 'px-6 py-2 rounded font-medium mx-3 shadow transition duration-200 each-in-out',
      outline: 'border',
      size: {
        sm: 'small',
        lg: 'large',
      },
    };
    
    const cx = classNames.bind(styles);
    
    console.log(cx('size.sm'));
    

    How can I access the size object?

    Reviewed by mybigman at 2021-07-29 00:27
  • 16. Fix bug where objects are converted to '[Object object]' in a VM

    Fixes #240

    I added a test case that fails against the original implementation.

    This comes with a bit of a perf hit but unfortunately there's no way around it if you want to reliably detect the native toString function. I made a JSBench so you can see the difference: https://jsbench.me/1xkpq8eozj

    Reviewed by markdalgleish at 2021-06-10 02:17
Encapsulated styling for your javascript components with all the power of javascript and CSS combined.

Stilr Encapsulated styling for your javascript components with all the power of javascript and CSS combined. Unique class names (Content Hash Based) U

May 30, 2022
Whirlwind is a utility-first styling framework specifically designed for React Native. It is heavily inspired by Tachyons and Tailwind CSS and uses low-level building blocks for rapidly building custom designs.

React Native Whirlwind ??️ A utility-first CSS framework designed for React Native. Whirlwind is a utility-first CSS framework specifically designed f

May 6, 2022
Court.css - A naive CSS Utility framework based on JSX and css custom properties

court.css ?? A (work in progress) JSX-based, CSS utility framework with a predic

Mar 14, 2022
JSS is an authoring tool for CSS which uses JavaScript as a host language.

JSS A lib for generating Style Sheets with JavaScript. For documentation see our docs. Backers Support us with a monthly donation and help us continue

Jun 23, 2022
Autoprefixer for JavaScript style objects

inline-style-prefixer A small, simple and fast vendor prefixer from JavaScript style object. Support Us Support Robin Frischmann's work on Fela and it

Jun 11, 2022
♞ JavaScript mobile-first chess.

♞ JavaScript mobile-first chess client. Play Documentation Changelog How does it work? The game state and the game view are separated. The view re-ren

May 23, 2022
A Simple Spinner and Loader Library for React
A Simple Spinner and Loader Library for React

React-Spinner A Simple Spinner and Loader Library Have a look How to use? The NPM package is not released yet. You can clone the project and try out t

May 21, 2022
Simple Portfolio Using React Hooks & Styled Components
Simple Portfolio Using React Hooks & Styled Components

Said MOUNAIM To view a live example, click here. Getting Started These instructi

Jun 16, 2022
A simple javascript utility for conditionally joining classNames together

Classnames A simple JavaScript utility for conditionally joining classNames together. Install with npm, Bower, or Yarn: # via npm npm install classnam

Jun 18, 2022
React-jsx-classnames - React JSX runtime for adding a classNames or clsx prop

@tpdewolf/react-jsx-classnames JSX runtime for adding a classNames or clsx prop.

Jan 15, 2022
A small utility for constructing classnames using a variant based api.

twix ?? twix is a small utility for constructing classnames using a variant based api. The API is largely copied from stitches but works with just pla

May 11, 2022
WunderGraph Demo joining Apollo Federation (with Subscriptions), REST and GraphQL APIs and consuming it from a NextJS application
 WunderGraph Demo joining Apollo Federation (with Subscriptions), REST and GraphQL APIs and consuming it from a NextJS application

This Repository demonstrates how to combine 7 APIs (4 Apollo Federation SubGraphs, 1 REST, 1 standalone GraphQL, 1 Mock) into one unified GraphQL API which is then securely exposed as a JSON API to a NextJS Frontend.

Jun 14, 2022
CRUD (Create, Read, Update, Delete) Recipe App with React. Project was developed together with DSC MMU during JavaScript Week 2021.
CRUD (Create, Read, Update, Delete) Recipe App with React. Project was developed together with DSC MMU during JavaScript Week 2021.

react-crud-recipe-app CRUD (Create, Read, Update, Delete) Recipe App with React. Project was developed together with DSC MMU during JavaScript Week 20

Jun 2, 2022
single-spa.js is an Open Source framework for bringing together multiple JavaScript microfrontends in a frontend application.

single-spa.js is an Open Source framework for bringing together multiple JavaScript microfrontends in a frontend application.

Feb 13, 2022
Functional typed classnames for TailwindCSS
Functional typed classnames for TailwindCSS

tailwindcss-classnames Functional typed classnames for TailwindCSS TailwindCSS is a CSS library that has gained a lot of traction. The developer exper

Jun 16, 2022
Dynamically classnames in React.

Reclsx Dynamically classnames in React Based on react/jsx-runtime Using classNames/dedupe Example import React from 'react'

Jun 18, 2022
Use the full power of React and GSAP together

react-gsap-enhancer Demos Why? How it works? Usage API A React component enhancer for applying GSAP animations on components without side effects. For

May 22, 2022
Trilha React Native - NLW Together (NLW 6) - Rocketseat
Trilha React Native - NLW Together (NLW 6) - Rocketseat

?? Technologies This project was developed using the following technologies: React Native Expo ?? Getting started Clone the project and access the fol

Aug 18, 2021
Project of Next Level Week Together - Q&A rooms
Project of Next Level Week Together - Q&A rooms

Letmeask Project of Next Level Week Together - Q&A rooms Features This app features all the latest tools and practices in web development! ⚛️ React Js

Aug 3, 2021
An "awesome" type curated list of how to use React Native and Meteor together
An

Awesome React Native Meteor An "awesome" type curated list of how to use React Native and Meteor together. Based on Awesome React Native which was bas

Feb 14, 2022