“cn” utility function in shadcn-ui/ui

May 26, 2024 (4mo ago)

When I saw the cn function being imported from @/lib/utils in shadcn-ui/ui source code, I assumed that this function’s name is derived from “shadcn” since it contains “cn’’and that it handles some core logic but turns out, it is a wrapper on top of clsx and twMerge. I questioned, Why? Why would you need such a wrapper?

To understand the reason behind this cn wrapper, you must first understand clsx and tailwind-merge.

Clsx

Clsx official docs definition is that it is a tiny (239B) utility for constructing className strings conditionally.

Also serves as a faster & smaller drop-in replacement for the classnames module.

### Examples:

import clsx from 'clsx';
// or
import { clsx } from 'clsx';

// Strings (variadic)
clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'

// Objects
clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'

// Objects (variadic)
clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });

We all are familiar with the clsx package, it is used to render the classnames conditionally.

Tailwind-merge:

To be honest, I have never used the tailwind-merge package before. So I visited the official docs and learnt that it is a utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.

Example:

import { twMerge } from 'tailwind-merge'

twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-\[#B91C1C\]')
// → 'hover:bg-dark-red p-3 bg-\[#B91C1C\]'

Connecting the dots:

It was at this point, it occurred to me that in shadcn-ui, clsx conditionally renders tailwind class names as strings and doing so could result in tailwind class name conflicts

Cn usage in shadcn-ui/ui:

I found the following files using cn function

https://github.com/search?q=repo%3Ashadcn-ui%2Fui+cn&type=code

References:

  1. https://github.com/shadcn-ui/ui/blob/main/apps/www/app/layout.tsx
  2. https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/utils.ts
  3. https://www.npmjs.com/package/tailwind-merge
  4. https://github.com/dcastil/tailwind-merge/blob/main/src/lib/create-tailwind-merge.ts
  5. https://github.com/dcastil/tailwind-merge/blob/main/src/lib/merge-classlist.ts#L6