UNPKG

5.84 kBMarkdownView Raw
1Classnames
2===========
3
4[![Version](http://img.shields.io/npm/v/classnames.svg)](https://www.npmjs.org/package/classnames)
5[![Build Status](https://travis-ci.org/JedWatson/classnames.svg?branch=master)](https://travis-ci.org/JedWatson/classnames)
6
7A simple javascript utility for conditionally joining classNames together.
8
9Install with npm or Bower.
10
11```sh
12npm install classnames
13```
14
15Use with node.js, browserify or webpack:
16
17```js
18var classNames = require('classnames');
19classNames('foo', 'bar'); // => 'foo bar'
20```
21
22Alternatively, 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.
23
24### Project philosophy
25
26We 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.
27
28Classnames follows the [SemVer](http://semver.org/) standard for versioning.
29
30There is also a [Changelog](https://github.com/JedWatson/classnames/blob/master/HISTORY.md).
31
32## Usage
33
34The `classNames` function takes any number of arguments which can be a string or object.
35The argument `'foo'` is short for `{ foo: true }`. If the value of the key is falsy, it won't be included in the output.
36
37```js
38classNames('foo', 'bar'); // => 'foo bar'
39classNames('foo', { bar: true }); // => 'foo bar'
40classNames({ 'foo-bar': true }); // => 'foo-bar'
41classNames({ foo: true }, { bar: true }); // => 'foo bar'
42classNames({ foo: true, bar: true }); // => 'foo bar'
43
44// lots of arguments of various types
45classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }) // => 'foo bar baz quux'
46
47// other falsy values are just ignored
48classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
49```
50
51Arrays will be recursively flattened as per the rules above:
52
53```js
54var arr = ['b', { c: true, d: false }];
55classNames('a', arr); // => 'a b c'
56```
57
58### Usage with React.js
59
60This package is the official replacement for `classSet`, which was originally shipped in the React.js Addons bundle.
61
62One 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:
63
64```js
65var Button = React.createClass({
66 // ...
67 render () {
68 var btnClass = 'btn';
69 if (this.state.isPressed) btnClass += ' btn-pressed';
70 else if (this.state.isHovered) btnClass += ' btn-over';
71 return <button className={btnClass}>{this.props.label}</button>;
72 }
73});
74```
75
76You can express the conditional classes more simply as an object:
77
78```js
79var classNames = require('classnames');
80
81var Button = React.createClass({
82 // ...
83 render () {
84 var btnClass = classNames({
85 'btn': true,
86 'btn-pressed': this.state.isPressed,
87 'btn-over': !this.state.isPressed && this.state.isHovered
88 });
89 return <button className={btnClass}>{this.props.label}</button>;
90 }
91});
92```
93
94Because 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:
95
96```js
97var btnClass = classNames('btn', this.props.className, {
98 'btn-pressed': this.state.isPressed,
99 'btn-over': !this.state.isPressed && this.state.isHovered
100});
101```
102
103
104### Alternate `dedupe` version
105
106There 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.
107
108This version is slower (about 10x) so it is offered as an opt-in.
109
110To use the dedupe version with node, browserify or webpack:
111
112```js
113var classNames = require('classnames/dedupe');
114
115classNames('foo', 'foo', 'bar'); // => 'foo bar'
116classNames('foo', { foo: false, bar: true }); // => 'bar'
117```
118
119For standalone (global / AMD) use, include `dedupe.js` in a `<script>` tag on your page.
120
121
122### Alternate `bind` version (for [css-modules](https://github.com/css-modules/css-modules))
123
124If you are using [css-modules](https://github.com/css-modules/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.
125
126```js
127var classNames = require('classnames/bind');
128
129var styles = {
130 foo: 'abc',
131 bar: 'def',
132 baz: 'xyz'
133}
134
135var cx = classNames.bind(styles);
136
137var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz"
138```
139
140Real-world example:
141
142```js
143/* components/submit-button.js */
144import { Component } from 'react';
145import classNames from 'classnames/bind';
146import styles from './submit-button.css';
147
148let cx = classNames.bind(styles);
149
150export default class SubmitButton extends Component {
151 render () {
152 let text = this.props.store.submissionInProgress ? 'Processing...' : 'Submit';
153 let className = cx({
154 base: true,
155 inProgress: this.props.store.submissionInProgress,
156 error: this.props.store.errorOccurred,
157 disabled: this.props.form.valid,
158 });
159 return <button className={className}>{text}</button>;
160 }
161}
162
163```
164
165
166## Polyfills needed to support older browsers
167
168#### `classNames >=2.0.0`
169
170`Array.isArray`: see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
171 for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill.
172`Object.keys`: see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill. This is only used in `dedupe.js`.
173
174## License
175
176[MIT](LICENSE)
177
\No newline at end of file