Skip to main content

cn()

The cn() function is a utility for merging and deduplicating class names with Tailwind CSS. It combines clsx for conditional class names with tailwind-merge for intelligent merging of Tailwind classes.

Function Signature

function cn(...inputs: ClassValue[]): string
inputs
ClassValue[]
Variable number of class values to merge. Accepts strings, objects, arrays, or any valid clsx input.
return
string
A merged and deduplicated class name string.

Features

  • Conditional Classes: Use objects or arrays for conditional class application
  • Tailwind Merge: Automatically resolves conflicting Tailwind classes
  • Type-Safe: Full TypeScript support with ClassValue type
  • Flexible Input: Accepts multiple argument formats

Usage Examples

Basic Usage

import { cn } from 'stride-ds';

// Simple merge
const className = cn('text-base', 'font-medium');
// Result: "text-base font-medium"

Conditional Classes

const className = cn(
  'button',
  isActive && 'active',
  isDisabled && 'disabled'
);
// Result: "button active" (if isActive is true)

Tailwind Conflict Resolution

const className = cn('px-2 py-1', 'p-4');
// Result: "p-4" (later padding value wins)

const className = cn('text-sm', 'text-base');
// Result: "text-base" (later font size wins)

With Objects

const className = cn({
  'bg-blue-500': isPrimary,
  'bg-gray-500': !isPrimary,
  'opacity-50': isDisabled
});

Component Props Pattern

interface ButtonProps {
  variant: 'primary' | 'secondary';
  className?: string;
}

const Button = ({ variant, className }: ButtonProps) => {
  return (
    <button
      className={cn(
        'base-button-styles',
        variant === 'primary' && 'primary-styles',
        variant === 'secondary' && 'secondary-styles',
        className // User overrides
      )}
    />
  );
};

With CVA (Class Variance Authority)

import { cva } from 'class-variance-authority';
import { cn } from 'stride-ds';

const buttonVariants = cva('button-base', {
  variants: {
    variant: {
      primary: 'bg-blue-500',
      secondary: 'bg-gray-500'
    },
    size: {
      sm: 'text-sm px-2',
      lg: 'text-lg px-4'
    }
  }
});

const Button = ({ variant, size, className }) => (
  <button className={cn(buttonVariants({ variant, size }), className)} />
);

Integration

The cn() utility integrates seamlessly with:
  • clsx: For conditional class name construction
  • tailwind-merge: For resolving Tailwind CSS class conflicts
  • class-variance-authority: For variant-based component styling
  • React Aria Components: For accessible component class management

Implementation

import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Why Use cn()?

  1. Avoids Class Conflicts: Automatically resolves Tailwind utility conflicts
  2. Cleaner Code: Simplifies conditional class logic
  3. Type Safety: Full TypeScript support
  4. Performance: Optimized for production use
  5. Standard Pattern: Widely adopted in the React ecosystem

Build docs developers (and LLMs) love