A simple javascript utility for conditionally joining classNames together

Related tags

React classnames
Overview

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. Copyright of the Typescript bindings are respective of each contributor listed in the definition file.

Comments
  • Ability to handle object with own `.toString()` method

    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?

    feature 
    opened by resetko 22
  • Update the package using the clsx implementation?

    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.

    question 
    opened by oliviertassinari 17
  • use [].join over concatenation

    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

    opened by dcousens 16
  • Use Array.isArray to check for array

    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

    opened by stuartsan 16
  • Importing classnames installed via NPM while using Webpack

    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!!

    question 
    opened by ramarivera 15
  • Take array as argument?

    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?

    question 
    opened by davidtheclark 14
  • Vast performance improvements;

    Vast performance improvements;

    Reworked all implementations (regular, dedupe, bind). No breaking changes.

    Benchmarks:

    > node ./benchmarks/run
    
    * local#strings x 15,466,941 ops/sec ±0.36% (92 runs sampled)
    *   npm#strings x 3,646,035 ops/sec ±1.69% (88 runs sampled)
    * local/dedupe#strings x 2,648,941 ops/sec ±0.19% (93 runs sampled)
    *   npm/dedupe#strings x 1,470,214 ops/sec ±1.71% (94 runs sampled)
    
    > Fastest is local#strings
    
    * local#object x 17,545,632 ops/sec ±0.42% (93 runs sampled)
    *   npm#object x 3,899,880 ops/sec ±1.32% (93 runs sampled)
    * local/dedupe#object x 7,118,462 ops/sec ±0.26% (91 runs sampled)
    *   npm/dedupe#object x 2,632,530 ops/sec ±0.16% (94 runs sampled)
    
    > Fastest is local#object
    
    * local#strings, object x 11,379,569 ops/sec ±0.44% (95 runs sampled)
    *   npm#strings, object x 3,259,972 ops/sec ±0.40% (94 runs sampled)
    * local/dedupe#strings, object x 2,525,953 ops/sec ±1.49% (93 runs sampled)
    *   npm/dedupe#strings, object x 1,548,802 ops/sec ±0.14% (92 runs sampled)
    
    > Fastest is local#strings, object
    
    * local#mix x 7,226,283 ops/sec ±0.20% (95 runs sampled)
    *   npm#mix x 2,521,931 ops/sec ±1.39% (93 runs sampled)
    * local/dedupe#mix x 907,851 ops/sec ±0.39% (93 runs sampled)
    *   npm/dedupe#mix x 667,852 ops/sec ±0.84% (95 runs sampled)
    
    > Fastest is local#mix
    
    * local#arrays x 3,571,391 ops/sec ±0.17% (94 runs sampled)
    *   npm#arrays x 919,980 ops/sec ±0.22% (91 runs sampled)
    * local/dedupe#arrays x 1,028,421 ops/sec ±1.41% (95 runs sampled)
    *   npm/dedupe#arrays x 743,585 ops/sec ±0.17% (94 runs sampled)
    
    > Fastest is local#arrays
    
    feature 
    opened by xobotyi 13
  • add typescript contributor copyright notice

    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
    question 
    opened by dcousens 13
  • Allow replacing of previous class names

    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.

    opened by longlho 13
  • speedup

    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

    feature 
    opened by silentroach 12
  • Use string concatenation, not arrays

    Use string concatenation, not arrays

    It seems like string concatenation is more performant than array manipulation, so I replaced classes.push( & classes.join(' ') with classes += ' ' +arg & classes.trimStart() in the core classnames function.

    All tests are passing, no new features were added. so I didn't add any new tests.

    jsperf.com from CONTRIBUTING.md doesn't work, so I tested on my machine and see massive performance gain in all cases: (local is the default, my is the changed one)

    * local#strings x 6,245,646 ops/sec ±1.00% (94 runs sampled)
    * my#strings x 9,570,213 ops/sec ±2.59% (97 runs sampled)
    
    > Fastest is my#strings
    
    * local#object x 7,165,102 ops/sec ±4.42% (95 runs sampled)
    * my#object x 12,929,752 ops/sec ±3.28% (99 runs sampled)
    
    > Fastest is my#object
    
    * local#strings, object x 5,413,534 ops/sec ±3.46% (90 runs sampled)
    * my#strings, object x 7,503,844 ops/sec ±2.32% (86 runs sampled)
    
    > Fastest is my#strings, object
    
    * local#mix x 3,176,253 ops/sec ±2.91% (89 runs sampled)
    * my#mix x 4,480,843 ops/sec ±2.08% (92 runs sampled)
    
    > Fastest is my#mix
    
    * local#arrays x 1,282,299 ops/sec ±1.22% (93 runs sampled)
    * my#arrays x 2,133,194 ops/sec ±1.08% (96 runs sampled)
    
    > Fastest is my#arrays
    
    feature 
    opened by fromaline 10
  • Interface types aren't compatible in 2.3.2

    Interface types aren't compatible in 2.3.2

    I meet a typing issue in 2.3.2:

    it worked on 2.3.1.

    import classNames from 'classnames';
    
    export interface ValidateType {
      error?: boolean;
    }
    
    const result: ValidateType | undefined = {
      error: true
    } as ValidateType;
    
    const data = classNames(result);
    console.log(`🚀 ~ file: index.ts ~ line 10 ~ data`, data);
    
    
    CleanShot 2022-11-11 at 19 58 56@2x
    [{
    	"resource": "/private/tmp/artin-QVhj2J/index.ts",
    	"owner": "typescript",
    	"code": "2345",
    	"severity": 8,
    	"message": "Argument of type '[ValidateType]' is not assignable to parameter of type 'ArgumentArray'.\n  Type 'ValidateType' is not assignable to type 'Argument'.\n    Type 'ValidateType' is not assignable to type 'Mapping'.\n      Index signature for type 'string' is missing in type 'ValidateType'.",
    	"source": "ts",
    	"startLineNumber": 11,
    	"startColumn": 25,
    	"endLineNumber": 11,
    	"endColumn": 31
    }]
    
    question types 
    opened by bytemain 2
  • Which class override the other one?

    Which class override the other one?

    Using classnames library, with react and module.scss styles, suppose I have a component like this:

    component.module.scss
    
    .red {
      color: red;
    }
    
    .blue {
      color: blue;
    }
    
    component.jsx
    import styles from './component.module.scss''
    
    const Component = ({ isBlue }) => (
      <span className={classnames(styles.red, { [styles.blue]: isBlue)} >
           This is a test
      </span>
    )
    

    As both classes are in the same file, I have some problems because there is usually a fixed class and I don't know how to prioritize the other over it. For example, in this example, the text will always be red unless I use an !important in the blue class.

    So the question is, how can I prioritize one class over another without using !important?

    additional info: is it possible that, as I am using placeholders in a different file, that I introduce a kind of "priority" between classes?

    question 
    opened by fjpedrosa 2
  • added dev-dep nyc to create coverage reports

    added dev-dep nyc to create coverage reports

    Hi there, I'm interested in seeing coverage reports for this projects so I installed nyc to work with the existing tools to create them. I noticed that there was an already ignored coverage folder, so I directed any output from nyc to enter that folder.

    Would you be open to running the test command with coverage as part of the build?

    Thanks!

    opened by achesin 0
  • Remove support for numbers

    Remove support for numbers

    Numbers are currently allowed, but they yield unexpected results

    > const classNames = require('classnames')
    > classNames(0)  // Falsy values are always filtered
    ''
    > classNames(42)  // Stringified integers aren’t valid class names
    '42'
    > classNames(3.14)  // Stringified floats aren’t valid class names
    '3.14'
    > classNames(Infinity)  // This is the only number which yields a valid class name
    'Infinity'
    > classNames(NaN)  // Falsy values are always filtered
    ''
    

    This may not be much of an issue, but the readme explicitly states this package is for joining class names. Numeric values aren’t valid class names, but they’re explicitly supported in the implementation.

    According to the type definitions, numbers are supported.

    Since breaking changes are on the way, I think it makes sense to remove support for numbers.

    breaking change types 
    opened by remcohaszing 6
Owner
Jed Watson
Jed Watson
Demo project to deploy front- and backend together on heroku.

spring-boot-react-bundle This is a demo project that shows how it is possible to deploy a react frontend and a Spring Boot backend into a heroku dyno.

André Schreck 5 Jul 22, 2022
A React utility belt for function components and higher-order components.

A Note from the Author (acdlite, Oct 25 2018): Hi! I created Recompose about three years ago. About a year after that, I joined the React team. Today,

Andrew Clark 14.8k Jan 4, 2023
Fully typed hooks and utility functions for the React Native StyleSheet API

react-native-style-utilities Fully typed hooks and utility functions for the React Native StyleSheet API npm i react-native-style-utilities ESLint Set

Marc Rousavy 73 Dec 17, 2022
React Native popup tip utility

react-native-tip React Native Tip is a simple package inspired in MaterialUI-Tooltip that helps you to show a quick tip to the user and highlight some

Maicon Gilton de Souza Freire 42 Jan 5, 2023
This web application aim to produce an contest notifier utility and a modern open-source compiler.

This web application aim to produce an contest notifier utility and a modern open-source compiler. The current features of the application include : Code Runner , Upcoming and Ongoing Contests.

ABHAY GUPTA 6 Dec 3, 2022
Javascript-Confirm-Dialogue - Simple Confirm Dialogue with 3 Options. Vanilla JS

Javascript Dialog Box v1.0.0 Javascript Dialog Box is a simple to use library for making dialog boxes in pure Javscript. It comes with the following f

Craig Hancock 0 Jan 12, 2022
Router JS 💽 Simple Router building in JavaScript

Router JS ?? Simple Router building in JavaScript

David Montaño Tamayo 1 Feb 12, 2022
A simple Web AI model deployment tool using JavaScript based on OpenCV.js and ONNXRuntime

WebAI.js 1. 简介 WebAI.js 是一个基于 OpenCV.js 和 ONNXRuntime 开发的一个 Web 前端 AI 模型部署工具 可通过在线体验网站 Hello WebAI.js 进行快速的体验试用 2. 特性 WebAI.js 支持 HTML script 标签引入和 no

AgentMaker 26 Nov 28, 2022
The best JavaScript Data Table for building Enterprise Applications. Supports React / Angular / Vue / Plain JavaScript.

Module SonarCloud Status ag-grid-community ag-grid-enterprise AG Grid AG Grid is a fully-featured and highly customizable JavaScript data grid. It del

AG Grid 9.5k Dec 30, 2022
Pickle tree - Javascript tree component made with pure javascript

Pickle Tree Pickle tree is a tree component written as completely pure javascript. Just send json file to object and have fun :-D Pickle tree does't n

Kadir Barış Bozat 17 Nov 13, 2022
Material-UI is a simple and customizable component library to build faster, beautiful, and more accessible React applications. Follow your own design system, or start with Material Design.

Material-UI Quickly build beautiful React apps. Material-UI is a simple and customizable component library to build faster, beautiful, and more access

Material-UI 83.6k Dec 30, 2022
⚡️ Simple, Modular & Accessible UI Components for your React Applications

Build Accessible React Apps with Speed ⚡️ Chakra UI provides a set of accessible, reusable, and composable React components that make it super easy to

Chakra UI 30.5k Jan 4, 2023
🐐 Simple and complete React DOM testing utilities that encourage good testing practices.

React Testing Library Simple and complete React DOM testing utilities that encourage good testing practices. Read The Docs | Edit the docs Table of Co

Testing Library 17.3k Jan 4, 2023
Simple React Bootstrap 4 components

reactstrap Stateless React Components for Bootstrap 4. Getting Started Follow the create-react-app instructions to get started and then follow the rea

reactstrap 10.4k Jan 5, 2023
🏎 A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components.

downshift ?? Primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components. Read the docs | See

Downshift 11.1k Dec 28, 2022
A simple tool that tells you what food is safe for your dog.

Can My Dog Eat A simple tool that tells you what food is safe for your dog. View website Features Can My Dog Eat is a simple website where you can loo

Isabelle Viktoria Maciohsek 25 Dec 11, 2022
Very simple app to decode your Vaccination Proof QR Code (such as the one provided by government of Quebec) - Compatible with SHC (Smart Health Card standard)

shc-covid19-decoder Visit simple hosted version on your phone (does NOT transmit any data, all remains in your browser) https://fproulx.github.io/shc-

François Proulx 148 Sep 23, 2022
simple static website generator

mkweb mkweb is a simple static website generator for NodeJS Features: Simple and fast Templates (currently hard coded to "template.html") Markdown wit

Rasmus 48 Nov 6, 2022
A simple PWA to scan your EU digital COVID Certificate and generate a passbook from it

COVID-19 passbook Generator The aim of this project is to let a user scan a EU Digital COVID Certificate with their smartphone, and generate a passboo

Thibault Milan 129 Nov 11, 2022