Skip to content

Styles

cn

1.0.0

Merges and deduplicates CSS class names with intelligent Tailwind CSS class handling. Combines clsx for conditional classes and tailwind-merge for Tailwind-specific merging, then deduplicates classes while preserving order.

cn(/inputs/);
  • Merges CSS classes intelligently with Tailwind support
  • Deduplicates classes while preserving order
  • Handles conditional classes via clsx
  • Resolves Tailwind class conflicts via tailwind-merge
  • Supports arrays, objects, and conditional expressions
  • Filters out falsy values automatically
  • Default export available for convenience
  • Comprehensive class processing pipeline
ArgTypeDefault ValueRequired
...inputsClassValue[]-No

Use the cn() function to merge and deduplicate CSS class names.

import { cn } from '@inpulse-ui/utils';
const result = cn('btn', 'btn-primary', 'w-full');
console.log(result); // "btn btn-primary w-full"

Handles conditional classes:

const isActive = true;
const isDisabled = false;
const classes = cn(
'btn',
'btn-primary',
isActive && 'active',
isDisabled && 'disabled'
);
console.log(classes); // "btn btn-primary active"

Merges Tailwind classes intelligently:

// Tailwind classes with conflicts
const classes = cn(
'bg-red-500',
'bg-blue-500', // This will override bg-red-500
'p-4',
'px-6' // This will override px part of p-4
);
console.log(classes); // "bg-blue-500 py-4 px-6"

Deduplicates identical classes:

const classes = cn(
'btn btn-primary',
'btn text-white',
'btn-primary hover:bg-blue-600'
);
console.log(classes); // "btn btn-primary text-white hover:bg-blue-600"

Works with arrays and objects:

const baseClasses = ['flex', 'items-center'];
const conditionalClasses = {
'justify-center': true,
'justify-between': false,
'space-x-2': true
};
const classes = cn(baseClasses, conditionalClasses, 'p-4');
console.log(classes); // "flex items-center justify-center space-x-2 p-4"

Form input component - building a flexible input with multiple variants and states:

import { cn } from '@inpulse-ui/utils';
function Input({
variant = 'default',
size = 'md',
error,
disabled,
className,
...props
}) {
const inputClasses = cn(
// Base styles
'w-full rounded-md border transition-colors focus:outline-none focus:ring-2',
// Size variants
{
'px-2 py-1 text-sm': size === 'sm',
'px-3 py-2 text-base': size === 'md',
'px-4 py-3 text-lg': size === 'lg'
},
// Variant styles
{
'border-gray-300 bg-white focus:border-blue-500 focus:ring-blue-500': variant === 'default',
'border-gray-400 bg-gray-100 focus:border-gray-600 focus:ring-gray-600': variant === 'filled',
'border-0 border-b-2 border-gray-300 bg-transparent rounded-none focus:border-blue-500': variant === 'underline'
},
// Error state
error && [
'border-red-500 bg-red-50 focus:border-red-500 focus:ring-red-500',
variant === 'underline' && 'bg-transparent'
],
// Disabled state
disabled && 'opacity-50 cursor-not-allowed bg-gray-100',
// Custom classes
className
);
return (
<input
className={inputClasses}
disabled={disabled}
{...props}
/>
);
}
// Usage examples
const examples = [
<Input placeholder="Default input" />,
<Input variant="filled" size="lg" placeholder="Large filled input" />,
<Input variant="underline" error placeholder="Underline with error" />,
<Input disabled placeholder="Disabled input" className="font-mono" />
];

React component styling:

// Button component with variants
function Button({ variant = 'primary', size = 'md', disabled, className, children }) {
const buttonClasses = cn(
// Base styles
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
// Size variants
{
'px-3 py-2 text-sm': size === 'sm',
'px-4 py-2 text-base': size === 'md',
'px-6 py-3 text-lg': size === 'lg'
},
// Color variants
{
'bg-blue-600 text-white hover:bg-blue-700': variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
'border border-gray-300 bg-white text-gray-700 hover:bg-gray-50': variant === 'outline'
},
// States
disabled && 'opacity-50 cursor-not-allowed',
// Custom classes
className
);
return <button className={buttonClasses}>{children}</button>;
}

Complex conditional styling:

function Card({ highlighted, error, loading, size, className }) {
const cardClasses = cn(
// Base styles
'rounded-lg border shadow-sm',
// Size variants
size === 'sm' && 'p-3',
size === 'md' && 'p-4',
size === 'lg' && 'p-6',
// State styles
highlighted && 'border-blue-500 bg-blue-50',
error && 'border-red-500 bg-red-50',
loading && 'animate-pulse',
// Default styles when no state
!highlighted && !error && 'border-gray-200 bg-white',
// Custom classes
className
);
return <div className={cardClasses}>Card content</div>;
}

Theme-based styling:

function ThemeProvider({ theme, children }) {
const themeClasses = cn(
// Base theme
'min-h-screen transition-colors',
// Theme variants
{
'bg-white text-gray-900': theme === 'light',
'bg-gray-900 text-white': theme === 'dark',
'bg-blue-50 text-blue-900': theme === 'blue'
}
);
return <div className={themeClasses}>{children}</div>;
}

Project

Built with by Jo Santana in Brazil.

© 2026 Inpulse. All rights reserved.