# Use cn() Utility for Class Merging

**MUST** · **ID:** `forms-ibelick-cn-utility` · **Category:** forms
**Source:** [@Ibelick](https://www.ui-skills.com/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/forms-ibelick-cn-utility

> MUST: Use cn utility (clsx + tailwind-merge) for conditional class logic. Handles class conflicts, falsy values, and array inputs cleanly.

Always use the cn() utility (clsx + tailwind-merge) for conditional and merged class names

From the Stack constraints in ibelick's baseline-ui skill. Naive string concatenation leaves both sides of a conflict in the class list (p-4 and p-2), and the winner is decided by stylesheet order, not by intent. cn() combines clsx for conditional logic with tailwind-merge for last-one-wins conflict resolution.

## Bad — do not do this

`forms-ibelick-cn-utility-bad`

```tsx
interface ButtonProps {
  variant?: 'default' | 'destructive';
  className?: string;
  children: React.ReactNode;
}

export function IbelickCnUtilityBad() {
  // Naive class concatenation without conflict resolution
  const Button = ({ variant = 'default', className = '', children }: ButtonProps) => {
    const baseClasses = 'px-4 py-2 rounded-lg font-medium p-4';
    const variantClasses = variant === 'destructive'
      ? 'bg-destructive text-destructive-foreground'
      : 'bg-primary text-primary-foreground';

    // Simple string concatenation - conflicts are not resolved
    const classes = `${baseClasses} ${variantClasses} ${className}`;

    return <button className={classes}>{children}</button>;
  };

  return (
    <div className="space-y-4">
      {/* p-4 from base conflicts with p-2 from className */}
      <Button className="p-2">Conflicting Padding</Button>
      <Button variant="destructive">Destructive</Button>
      <p className="text-xs text-destructive mt-4">
        String concatenation doesn't resolve p-4 vs p-2 conflicts
      </p>
    </div>
  );
}
```

## Good — do this

`forms-ibelick-cn-utility-good`

```tsx
import { cn } from '@/lib/utils';

interface ButtonProps {
  variant?: 'default' | 'destructive';
  className?: string;
  children: React.ReactNode;
}

export function IbelickCnUtilityGood() {
  // Using cn() utility for intelligent class merging
  const Button = ({ variant = 'default', className, children }: ButtonProps) => {
    return (
      <button
        className={cn(
          'px-4 py-2 rounded-lg font-medium p-4',
          variant === 'destructive'
            ? 'bg-destructive text-destructive-foreground'
            : 'bg-primary text-primary-foreground',
          className // cn() intelligently resolves conflicts
        )}
      >
        {children}
      </button>
    );
  };

  return (
    <div className="space-y-4">
      {/* p-2 from className correctly overrides p-4 from base */}
      <Button className="p-2">Override Padding</Button>
      <Button variant="destructive">Destructive</Button>
      <p className="text-xs text-success mt-4">
        cn() resolves conflicts: p-2 correctly overrides p-4
      </p>
    </div>
  );
}
```

## References

- [baseline-ui (skill source)](https://github.com/ibelick/ui-skills/blob/main/skills/baseline-ui/SKILL.md)
- [tailwind-merge](https://github.com/dcastil/tailwind-merge)
