A tiny (239B) utility for constructing className strings conditionally.
clsx is a minimalist utility function designed to solve one problem exceptionally well: constructing CSS className strings from conditional inputs. Instead of manually concatenating strings or writing ternary operations for every dynamic class, clsx accepts mixed input types—strings, objects, arrays, and booleans—and returns a clean, space-separated string of valid class names.
The package emerged as a performance-focused alternative to the classnames library, which had become ubiquitous in React applications but carried unnecessary weight for most use cases. At just 239 bytes, clsx achieves the same core functionality with significantly better performance by making pragmatic trade-offs: it skips certain safety checks like hasOwnProperty and explicit Array.isArray calls that are rarely needed in modern JavaScript environments.
With over 47 million weekly downloads, clsx has become the de facto choice for conditional styling in React, Vue, Svelte, and vanilla JavaScript projects. Its adoption spans from small side projects to major production applications at scale. The library's stability is reflected in its maintenance status—minimal updates over the past year indicate a mature, battle-tested codebase rather than abandonment.
Developers choose clsx when bundle size matters and when the straightforward API aligns with their mental model. It works seamlessly with CSS Modules, Tailwind CSS, styled-components, and any other styling approach that requires dynamic className composition. The library has no dependencies, supports modern ESM imports, and integrates into any build pipeline without configuration.
import clsx from 'clsx';
import { useState } from 'react';
function Button({ variant = 'primary', size = 'medium', disabled = false, children }) {
const [isPressed, setIsPressed] = useState(false);
const buttonClasses = clsx(
'btn',
`btn--${variant}`,
`btn--${size}`,
{
'btn--disabled': disabled,
'btn--pressed': isPressed,
'btn--interactive': !disabled
},
isPressed && 'scale-95 transition-transform'
);
return (
<button
className={buttonClasses}
disabled={disabled}
onMouseDown={() => !disabled && setIsPressed(true)}
onMouseUp={() => setIsPressed(false)}
onMouseLeave={() => setIsPressed(false)}
>
{children}
</button>
);
}
function FormInput({ value, error, touched, required }) {
return (
<div className={clsx('form-field', { 'form-field--required': required })}>
<input
className={clsx(
'input',
'input--bordered',
touched && error && 'input--error',
touched && !error && value && 'input--valid'
)}
value={value}
/>
{touched && error && <span className="error-message">{error}</span>}
</div>
);
}React component conditional styling: Toggle CSS classes based on component props or state, such as applying 'active', 'disabled', or 'error' classes without verbose string concatenation or ternary operators scattered throughout JSX.
Tailwind CSS dynamic utilities: Combine static Tailwind utility classes with conditional variants based on application state, user preferences, or responsive conditions, keeping the className attribute readable even with dozens of utilities.
Form validation feedback: Apply different CSS classes to form inputs and their containers based on validation state (pristine, touched, valid, invalid, loading), making it easy to coordinate visual feedback across multiple elements.
Theme switching: Dynamically apply theme-specific class names based on user preferences or system settings, combining base component classes with theme modifier classes in a clean, declarative way.
Component variant systems: Build design system components with multiple variants (size, color, style) where each variant maps to specific CSS classes, using objects to conditionally apply the correct combination based on props.
npm install clsxpnpm add clsxbun add clsx