@lightsound/cn
v1.2.1
Published
A tiny, blazing fast utility for constructing className strings conditionally
Downloads
590
Maintainers
Readme
@lightsound/cn
A tiny, blazing fast utility for constructing className strings conditionally.
Features
- Blazing Fast: Up to 50% faster than
clsx/lite - Tiny: ~130B gzipped (smaller than clsx/lite!)
- TypeScript: Full type support out of the box
- Simple API: Strings only - no objects, no arrays, maximum performance
- Zero Dependencies: No external dependencies
Why @lightsound/cn?
| Feature | @lightsound/cn | clsx/lite | clsx | | --------------- | -------------- | --------- | ----- | | Strings only | ✅ | ✅ | ❌ | | Objects support | ❌ | ❌ | ✅ | | Arrays support | ❌ | ❌ | ✅ | | Size (gzip) | ~130B | ~141B | ~239B | | Performance | ⚡⚡⚡ | ⚡⚡ | ⚡ |
If you only use string-based class composition (the most common pattern with Tailwind CSS), @lightsound/cn provides the best performance.
Benchmarks
Benchmarks are run on every CI build. See the latest CI run for up-to-date results.
| Test Case | @lightsound/cn | clsx/lite | Improvement | | ---------- | -------------- | --------- | -------------- | | 2 strings | 20.76 ns | 41.56 ns | 50% faster | | 3 strings | 47.25 ns | 62.71 ns | 25% faster | | 5 strings | 62.90 ns | 83.75 ns | 25% faster | | 10 strings | 104.68 ns | 135.50 ns | 23% faster |
- Runs: 30 iterations per scenario
- Iterations: 100,000 operations per run
- Outlier removal: Top and bottom 10% trimmed
- Metric: Median (more stable than mean)
- Warmup: 10,000 iterations before measurement
Installation
# npm
npm install @lightsound/cn
# pnpm
pnpm add @lightsound/cn
# yarn
yarn add @lightsound/cn
# bun
bun add @lightsound/cnUsage
import { cn } from "@lightsound/cn";
// or
import cn from "@lightsound/cn";
// Basic usage
cn("foo", "bar");
// => 'foo bar'
// Conditional classes
cn("btn", isActive && "btn-active", isDisabled && "btn-disabled");
// => 'btn btn-active' (if isActive is true, isDisabled is false)
// With ternary expressions
cn("btn", variant === "primary" ? "btn-primary" : "btn-secondary");
// => 'btn btn-primary'
// Falsy values are ignored
cn("foo", false, null, undefined, 0, "", "bar");
// => 'foo bar'API
cn(...classes)
Combines class names into a single string. Only accepts strings - non-string values (falsy values) are ignored.
Parameters
...classes:(string | false | null | undefined | 0)[]- Any number of class name strings or falsy values
Returns
string- The combined class names separated by spaces
Compatibility with clsx/lite
@lightsound/cn is designed as a faster, drop-in replacement for clsx/lite:
// Before
import clsx from "clsx/lite";
clsx("btn", isActive && "active", "btn-primary");
// After
import { cn } from "@lightsound/cn";
cn("btn", isActive && "active", "btn-primary");TypeScript Users
You're fully covered! The type definition only accepts string | false | 0 | null | undefined, so passing objects or arrays will result in a compile-time error:
cn("btn", { active: true }); // ❌ TypeScript error
cn("btn", ["a", "b"]); // ❌ TypeScript error
cn("btn", isActive && "active"); // ✅ Works perfectlyJavaScript Users
Note that runtime behavior differs from clsx/lite when passing unsupported types:
| Input | clsx/lite | @lightsound/cn |
| ------------------ | --------- | ------------------- |
| { active: true } | "" | "[object Object]" |
| ["a", "b"] | "" | "a,b" |
If you're using JavaScript, ensure your codebase only passes strings and falsy values to cn().
Using with Tailwind Merge
If you need to merge Tailwind CSS classes (resolving conflicts like px-2 and p-3), use tc from @lightsound/cn/tw-merge:
# Install tailwind-merge as a peer dependency
bun add tailwind-mergeimport { tc } from "@lightsound/cn/tw-merge";
// Conflicting classes are merged intelligently
tc("px-2 py-1", "p-3");
// => 'p-3'
tc("text-red-500", "text-blue-500");
// => 'text-blue-500'
tc("bg-gray-100 text-gray-900", "bg-blue-500 text-white");
// => 'bg-blue-500 text-white'
// Works with conditional classes too
tc("text-gray-500", isActive && "text-blue-500");
// => 'text-blue-500' (if isActive is true)Note:
tcrequirestailwind-mergeto be installed separately. If you only needcn, you don't need to installtailwind-merge.
Tailwind CSS IntelliSense
To enable Tailwind CSS IntelliSense for cn() and tc(), add this to your VS Code settings:
{
"tailwindCSS.experimental.classRegex": [
["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"],
["tc\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
}License
MIT © lightsound
