What is Tailwind-merge and how to use it?

Tailwind-merge is a utility function library that allows merging Tailwind CSS classes efficiently without any conflicts.

The issue that Tailwind-merge is trying to fix is when CSS class names are added conditionally, they may be ignored because of the way the CSS cascade operates. In a nutshell, the CSS cascade determines how the browser processes CSS rules when rendering a page. It takes into account factors such as specificity, importance, and order to reconcile conflicting rules. In Tailwind, using conditional class names may result in the latest CSS rules overwriting the previous ones, or the output class names may not be the expected result.

Tailwind-merge can assist us to resolve these types of issues by creating a new string that will contain the optimized and expected class names.

// Example without Tailwind-merge
function RecipeCard(props) {
  const cardStyles = `border shadow-md p-4 ${props.customStyles || ""}`
  return (
    <div className={cardStyles}>
      <h2 className="text-xl font-semibold">{props.title}</h2>
      <p className="text-gray-600">{props.description}</p>
    </div>
  )
}
// Example with Tailwind-merge
function RecipeCard(props) {
  const cardStyles = twMerge("border shadow-md p-4", props.className)
  return (
    <div className={cardStyles}>
      <h2 className="text-xl font-semibold">{props.title}</h2>
      <p className="text-gray-600">{props.description}</p>
    </div>
  )
}

Combined with the "clsx" library.

You are probably already familiar with the library clsx to handle conditional classNames. This library can construct classNames strings conditionally with ease, but it is important to know that it doesn’t fix the CSS conflicts that may arrive when using Tailwind.

The maintainers of the Tailwind-merge library propose an alternative to this solution in a GitHub discussion.

import clsx from "clsx"
import { twMerge as twMergeOriginal } from "tailwind-merge"
 
export function twMerge(...args) {
  return twMergeOriginal(clsx(args))
}

In this example, we use clsx to handle the conditional class names by passing the arguments into it as clsx(args). The resulting output is then passed into twMergeOriginal to resolve any potential CSS conflicts.

This pattern has also been greatly demonstrated in the shadcn-ui project. I'm a big fan of this project and plan to write a dedicated article about it soon.

// Source: https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/utils.ts
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

I hope this article helps you to understand how we can use Tailwind-merge and the issues it can resolve. I also wanted to demonstrate how we can integrate it with the clsx library to create a useful utility function.

I highly recommend reading the tailwind-merge documentation if you want to gain a better understanding of how it operates and the potential trade-offs to consider when using this library.