# Writing conditional tailwind classNames.

You want to add a style to a div when a particular state in your app is true? You can achieve this using this library.

In your Next.js or React app create a folder in root directory and name it as "lib". Inside lib folder create a file named "utils.ts" or "utils.js" based on the language of your choice.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706187197976/bfe393ef-7fb7-4c82-8521-08f688fc9116.png align="center")

## Installing packages

Run this below command to install these npm package:

```bash
npm i clsx
npm i tailwind-merge
```

## Below it's explained what these libraries do? skip this section if not interested.

### Tailwind Merge.

If you use Tailwind CSS with a component-based UI renderer like [React](https://reactjs.org) or [Vue](https://vuejs.org), you're probably familiar with the situation that you want to change some styles of a component, but only in a one-off case.

```bash
// React components with JSX syntax used in this example

function MyGenericInput(props) {
    const className = `border rounded px-2 py-1 ${props.className || ''}`
    return <input {...props} className={className} />
}

function MyOneOffInput(props) {
    return (
        <MyGenericInput
            {...props}
            className="p-3" // ← Only want to change some padding
        />
    )
}
```

When `MyOneOffInput` is rendered, an input with the className `border rounded px-2 py-1 p-3` gets created. But because of the way the [CSS cascade](https://developer.mozilla.org/en-US/docs/Web/CSS/Cascade) works, the styles of the `p-3` class are ignored. The order of the classes in the `className` string doesn't matter at all and the only way to apply the `p-3` styles is to remove both `px-2` and `py-1`.

This is where tailwind-merge comes in.

```bash
function MyGenericInput(props) {
    // ↓ Now `props.className` can override conflicting classes
    const className = twMerge('border rounded px-2 py-1', props.className)
    return <input {...props} className={className} />
}
```

tailwind-merge overrides conflicting classes and keeps everything else untouched. In the case of the `MyOneOffInput`, the input is now rendered with the classes `border rounded p-3`.

### CLSX:

### Usage

```bash
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' });
//=> 'foo --foobar'

// Arrays
clsx(['foo', 0, false, 'bar']);
//=> 'foo bar'

// Arrays (variadic)
clsx(['foo'], ['', 0, false, 'bar'], [['baz', [['hello'], 'there']]]);
//=> 'foo bar baz hello there'

// Kitchen sink (with nesting)
clsx('foo', [1 && 'bar', { baz:false, bat:null }, ['hello', ['world']]], 'cya');
//=> 'foo bar hello world cya'
```

### API

### cl[sx(..](https://github.com/lukeed/clsx#API).input)

Retu[rns](https://github.com/lukeed/clsx#API): `String`

#### in[put](https://github.com/lukeed/clsx#API)

Type[: `M`](https://github.com/lukeed/clsx#API)`ixed`

The [`cls`](https://github.com/lukeed/clsx#API)`x` function can take ***any*** number of arguments, each of which can be an Object, Array, Boolean, or String.

> **Impo**[**rta**](https://github.com/lukeed/clsx#API)\*\*nt:\*\**Any* falsey values are discarded!  
> Standalone Boolean values are discarded as well.

```bash
clsx(true, false, '', null, undefined, 0, NaN);
//=> ''
```

### Mo[des](https://github.com/lukeed/clsx#API)

Ther[e a](https://github.com/lukeed/clsx#API)re multiple "versions" of `clsx` available, which allows you to bring only the functionality you need!

#### `cl`[`sx`](https://github.com/lukeed/clsx#API)

> **Size**[**(g**](https://github.com/lukeed/clsx#API)**zip):** 239 bytes  
> **Availability:** CommonJS, ES Module, UMD

The [def](https://github.com/lukeed/clsx#API)ault `clsx` module; see [API](https://github.com/lukeed/clsx#API) for info.

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

#### `cl`[`sx/li`](https://github.com/lukeed/clsx#API)`te`

> **Size**[**(g**](https://github.com/lukeed/clsx#API)**zip):** 140 bytes  
> **Availability:** CommonJS, ES Module  
> **CAUTION:** Accepts **ONLY** string arguments!

Idea[l f](https://github.com/lukeed/clsx#API)or applications that ***only*** use the string-builder pattern.

Any [non](https://github.com/lukeed/clsx#API)\-string arguments are ignored!

```bash
import { clsx } from 'clsx/lite';
// or
import clsx from 'clsx/lite';

// string
clsx('hello', true && 'foo', false && 'bar');
// => "hello foo"

// NOTE: Any non-string input(s) ignored
clsx({ foo: true });
//=> "
```

## After installing the above packages, paste this code in utils.ts file.

```typescript
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

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

## Now we will create a component to understand how we can use this cn function we created.

Our goal is to create a button that changes it's color from blue to green or green to blue when clicked on it. The completed work will look like this.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706192356757/ade64088-1de9-41eb-acf2-bfb1789efef3.gif align="center")

Now create a file named "Demo.tsx" and paste this below code in it.

```typescript
'use client';

import { useState } from 'react';

interface DemoProps {}

export const Demo = ({}: DemoProps) => {
  const [state, setState] = useState(true);
  return (
    <div className='flex'>
      <button
        type='button'
        className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800'
      >
        Click me to change the color of me
      </button>
    </div>
  );
};
```

Add this above component to your main component, in our case it's: 'src/app/page.tsx'.

```typescript
import { Demo } from '@/components/Demo';

export default function Home() {
  return (
    <main className='w-full h-screen flex items-center justify-center'>
      <Demo />
    </main>
  );
}
```

Now the app looks like this.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706192781006/8d2f2e92-f3f6-4680-b0a4-4cbc988c8f71.png align="center")

Clicking on it will do nothing as of now.

Now go to Demo.tsx and import cn function to it.

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

Modify your button to below code.

```xml
<button
    type='button'
    onClick={() => setState(!state)}
    className={cn(
        'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800',
        state &&
        'focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800'
        )}
>
    Click me to change the color of me
</button>
```

In the above code we added an onClick event to the button that negates the state value when clicked on it. we modified className to use cn function. The final code looks like this.

```typescript
'use client';

import { cn } from '@/lib/utils';
import { useState } from 'react';

interface DemoProps {}

export const Demo = ({}: DemoProps) => {
  const [state, setState] = useState(false);
  return (
    <div className='flex'>
      <button
        type='button'
        onClick={() => setState(!state)}
        className={cn(
          !state &&
            'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800',
          state &&
            'focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800'
        )}
      >
        Click me to change the color of me
      </button>
    </div>
  );
};
```

The above code is a React component named Demo. It is a functional component that doesn't take any props. Let's break down the code step by step:

1. **useState Hook**: The component uses the `useState` hook from React to create a state variable `state` and a function `setState` to update this state. The initial value of `state` is `false`.
    
2. **JSX**: Inside the `return` statement, the component returns JSX, which represents the UI. It consists of a `div` element with a class name of 'flex' and a `button` element.
    
3. **Button**: The button has an `onClick` event handler that toggles the value of `state` when clicked. It also has a dynamic class name based on the value of `state`. The `cn` function is used to conditionally apply class names based on the value of `state`.
    
4. **Conditional Class Names**: The `cn` function is used to conditionally apply class names to the button based on the value of `state`. When `state` is `false`, it applies a set of classes related to the blue color scheme, and when `state` is `true`, it applies a set of classes related to the green color scheme.
    
5. **Button Text**: The button text says "Click me to change the color of me".
    

In summary, this component renders a button that changes its color when clicked, toggling between blue and green, and the color change is reflected in the button's appearance based on the state value.

## Summary

Using 'clsx' and 'tailwind merge' we can write conditional classes.
