✅ Accepts strings, arrays, objects, booleans, null, and undefined
✅ Filters out falsy values
✅ Automatically resolves conflicting Tailwind classes like p-2 vs p-4
✅ Works seamlessly with any styling framework (not just Tailwind)
Install via npm or yarn:
npm install classnames-merge-tw
or
yarn add classnames-merge-tw
import { cn } from 'classnames-merge-tw';
// Strings
cn('btn', true && 'btn-primary', false && 'btn-disabled');
//=> 'btn btn-primary'
// Objects
cn({ btn: true, 'btn-disabled': false });
//=> 'btn'
// Arrays
cn(['btn', false && 'hidden', 'btn-active']);
//=> 'btn btn-active'
// Complex combinations
cn('text-lg', ['font-bold', { 'text-gray-500': isDisabled }], someClass);
//=> 'text-lg font-bold text-gray-500'
Unlike basic className utilities, this package intelligently handles conflicting Tailwind classes.
cn('p-4', 'p-2', 'bg-red-500', 'bg-blue-500');
//=> 'p-2 bg-blue-500'
//=> Only the last applied utility from each group (padding, background, etc.) is kept — just like tailwind-merge.
- cn(...classNames)
- classNames: any combination of strings, arrays, booleans, null, undefined, or objects like { 'class': condition }
cn(true, false, '', null, undefined, 0, NaN);
//=> ''
- Bootstrap
cn('btn', 'btn-primary', { active: isActive });
//=> 'btn btn-primary active'
- Material-UI
cn('MuiButton-root', { 'MuiButton-disabled': isDisabled });
//=> 'MuiButton-root MuiButton-disabled'
- Ant Design
cn('ant-btn', 'ant-btn-primary', { 'ant-btn-dangerous': isDanger });
//=> 'ant-btn ant-btn-primary ant-btn-dangerous'
MIT © Lavisar