“cn” utility function in shadcn-ui/ui:
Tags: javascript, nextjs, opensource, shadcnui
Published: 2024-05-23 20:57:31

When I saw the [cn function](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/utils.ts#L5) being imported from [@/lib/utils](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/utils.ts#L5) 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](https://www.npmjs.com/package/clsx) and [twMerge](https://www.npmjs.com/package/tailwind-merge). 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](https://www.npmjs.com/package/clsx) definition is that it is a tiny (239B) utility for constructing className strings conditionally.

Also serves as a [faster](https://github.com/lukeed/clsx/blob/HEAD/bench) & smaller drop-in replacement for the classnames module.

> [_Build shadcn-ui/ui from scratch._](https://tthroo.com/)

```
### 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](https://www.npmjs.com/package/tailwind-merge) and learnt that it is a utility function to efficiently merge [Tailwind CSS](https://tailwindcss.com/) 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

![](https://media.licdn.com/dms/image/D4E12AQFr3TGiswTcmw/article-inline_image-shrink_1500_2232/0/1716496517558?e=1721865600&v=beta&t=S8ggmWFLnIzDVeAbPEdARLI0XECo3r8wrWldagZeShc)

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](https://github.com/search?q=repo%3Ashadcn-ui%2Fui+cn&type=code)

![](https://media.licdn.com/dms/image/D4E12AQHLWtERa9TX4Q/article-inline_image-shrink_1500_2232/0/1716496518223?e=1721865600&v=beta&t=9qTXu6eltXVdTJNmHQYVZ94cxUBpcW4_vwkVeXgw57c)

References:
-----------

1.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/app/layout.tsx](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](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/utils.ts)
3.  [https://www.npmjs.com/package/tailwind-merge](https://www.npmjs.com/package/tailwind-merge)
4.  [https://github.com/dcastil/tailwind-merge/blob/main/src/lib/create-tailwind-merge.ts](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](https://github.com/dcastil/tailwind-merge/blob/main/src/lib/merge-classlist.ts#L6)