One more DOM classname string builder if you not enough yet 😁
It is lightweight, fast and has no dependencies!
Install it via npm or yarn
npm i cnbuilder
yarn add cnbuilder
Use it wherever and however you want - node.js or webpack, CJS or ESM modules!
var cnb = require("cnbuilder");
cnb("cnbuilder", { is: true }, ["awesome!"]);
import cnb from "cnbuilder";
cnb("works", { with: true }, ["ESM!"]);
Or even just include it with a standalone <script>
tag from CDNJS
<script src="https://cdnjs.cloudflare.com/ajax/libs/cnbuilder/1.0.0/cnbuilder.js" />
<script type="application/javascript">
(() => {
cnbuilder("Hello", ["world!"]);
})();
</script>
Why
cnbuilder
is designed to be as lightweight and fast as possible, without loosing the functionality (jorgebucaran/classcat is faster in some cases but less handy because does not allow to pass variable count of arguments).
It is written with power of TypeScript and it's API is fully compatible with JedWatson/classnames, so it wont be anyhow hard to migrate for you if you're already using classnames
package.
Usage
As already said - API is the same with classnames
pkg, and due to my laziness - i'll just copy-past their usage documentation (width small additions)😅😱
The classNames
function takes any number of arguments which can be a string, array or object.
The argument 'foo'
is short for { foo: true }
or ['foo']
. If the value associated with a given key is falsy, that key won't be included in the output.
cnb("foo", "bar");
cnb("foo", { bar: true });
cnb({ "foo-bar": true });
cnb({ "foo-bar": false });
cnb({ foo: true }, { bar: true });
cnb({ foo: true, bar: true });
cnb("foo", { bar: true, duck: false }, "baz", { quux: true });
cnb(null, false, "bar", undefined, 0, 1, { baz: null }, "");
Arrays will be recursively flattened as per the rules above:
var arr = ["b", { c: true, d: false }];
cnb("a", arr);
BUT! there are two additions, comparing to classnames
result generation:
- it does not generate useless spaces:
classnames("test", [], { a: false });
cnb("test", [], { a: false });
- it skips fully numeric classnames, due to classnames starting with digit are illegal, but it can't skip strings starting with digit, cause it would impact the performance, so that part is left for the end developer
classnames(321, "1stPlace");
cnb(321, "1stPlace");
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";
cnb({ [`btn-${buttonType}`]: true });
Polyfills needed to support older browsers
Array.isArray
: see MDN for details about unsupported older browsers (e.g. <= IE8) and a simple polyfill.
Array.reduce
: see MDN for details about unsupported older browsers (e.g. <= IE10) and a simple polyfill.
Performance (recent benchmarks results)
benchmarks ran on 3.4GHz Core i7 CPU width 16GB DDR4 RAM
npm run build && npm i -C benchmark && npm -C benchmark start
# STRINGS
cnbuilder × 8,836,828 ops/sec;
classcat × 8,400,103 ops/sec;
classnames × 2,965,358 ops/sec;
clsx × 8,655,090 ops/sec;
# OBJECTS
cnbuilder × 5,882,489 ops/sec;
classcat × 6,524,113 ops/sec;
classnames × 2,542,451 ops/sec;
clsx × 5,025,306 ops/sec;
# ARRAYS
cnbuilder × 4,800,036 ops/sec;
classcat × 5,858,583 ops/sec;
classnames × 1,173,988 ops/sec;
clsx × 1,179,686 ops/sec;
# NESTED ARRAYS
cnbuilder × 3,090,131 ops/sec;
classcat × 1,427,428 ops/sec;
classnames × 822,602 ops/sec;
clsx × 674,716 ops/sec;
# OBJECTS NESTED IN ARRAYS
cnbuilder × 3,361,427 ops/sec;
classcat × 4,805,079 ops/sec;
classnames × 1,099,372 ops/sec;
clsx × 1,003,921 ops/sec;
# MIXED
cnbuilder × 3,636,334 ops/sec;
classcat × 5,284,783 ops/sec;
classnames × 1,533,224 ops/sec;
clsx × 1,639,769 ops/sec;