classnames README

The project's README from github.com/JedWatson/classnames. As one markdown file: README.md.

Classnames

A simple JavaScript utility for conditionally joining classNames together.

Install from the npm registry with your package manager:

npm install classnames

Use with Node.js, Browserify, or webpack:

const 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 implications 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, { baz: null }, ''); // => 'bar'

// conditional strings (falsy results are ignored)
classNames('foo', true && 'bar'); // => 'foo bar'
classNames('foo', false && 'bar'); // => 'foo'

Arrays will be recursively flattened as per the rules above:

const 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:

const 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:

import React, { useState } from 'react';

export default function Button (props) {
  const [isPressed, setIsPressed] = useState(false);
  const [isHovered, setIsHovered] = useState(false);

  let btnClass = 'btn';
  if (isPressed) btnClass += ' btn-pressed';
  else if (isHovered) btnClass += ' btn-over';

  return (
    <button
      className={btnClass}
      onMouseDown={() => setIsPressed(true)}
      onMouseUp={() => setIsPressed(false)}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {props.label}
    </button>
  );
}

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

import React, { useState } from 'react';
import classNames from 'classnames';

export default function Button (props) {
  const [isPressed, setIsPressed] = useState(false);
  const [isHovered, setIsHovered] = useState(false);

  const btnClass = classNames({
    btn: true,
    'btn-pressed': isPressed,
    'btn-over': !isPressed && isHovered,
  });

  return (
    <button
      className={btnClass}
      onMouseDown={() => setIsPressed(true)}
      onMouseUp={() => setIsPressed(false)}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {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:

const btnClass = classNames('btn', this.props.className, {
  'btn-pressed': isPressed,
  'btn-over': !isPressed && 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:

const 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.

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

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

const cx = classNames.bind(styles);

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

Real-world example:

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

const cx = classNames.bind(styles);

export default function SubmitButton ({ store, form }) {
  const [submissionInProgress, setSubmissionInProgress] = useState(store.submissionInProgress);
  const [errorOccurred, setErrorOccurred] = useState(store.errorOccurred);
  const [valid, setValid] = useState(form.valid);

  const text = submissionInProgress ? 'Processing...' : 'Submit';
  const className = cx({
    base: true,
    inProgress: submissionInProgress,
    error: errorOccurred,
    disabled: 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.

classnames (JedWatson/classnames)

Searching Database…

这是什么?一个很小的 JavaScript 工具,可以按条件把 className 字符串拼接在一起,常用于为 React 和其他 UI 代码构建动态的 'className' 属性。
这个工具只能用于 React 吗?别的东西也能用吗?它与框架无关,你可以在 Node.js、Browserify 或 webpack 打包工具中使用,也可以直接把 index.js 放到页面上,作为独立脚本或 AMD 脚本使用。它与 React 搭配尤其好。
我该如何把它加入我的项目?用你的包管理器从 npm 仓库安装(例如 npm install classnames),然后在 Node、Browserify 或 webpack 环境中导入;如果要独立使用,也可以通过 script 标签直接引入 index.js。
它会引入其他依赖吗?不会,它没有运行时依赖,只是一个可以直接安装的小函数。
要支持老版本浏览器,我需要用到 polyfill 吗?需要。对于 classNames >=2.0.0 版本,如果要支持 IE8 及更低版本的浏览器,你需要一个 Array.isArray 的 polyfill。
默认版本和去重版本有什么区别?去重版本会正确移除重复的类名,并排除后面参数中指定的假值类名,但速度大约慢 5 倍,所以它作为需要主动选择的替代导入方式提供。
什么时候会用到 bind 变体?bind 变体面向 css-modules 风格的工作流程:你可以先把一个 styles 对象绑定好,再把样式名映射为实际输出的 className。它与动态键的做法类似,但可以反复使用。
我能用计算属性键动态构建类名吗?可以。在支持计算属性键的 ES2015/Babel 环境中,你可以直接用动态属性名来构造 className 对象。
这是用来替代 React 本身的某个功能吗?是的,它是 React.js Addons 包中曾经提供的 classSet 工具的官方替代品。
Creator
JedWatson
Size
0.9 MB
Stars
17.8K
Updated
CommitAug 05
Age
11y
Commits · 90 Days