React – shadcn/ui のユーティリティ関数 cn() について解説

概要

shadcn/ui ライブラリのユーティリティ関数 cn() は、複数の CSS クラス名を結合し、Tailwind CSS のクラス名の競合を解決する便利な関数です。 この記事では、この cn() 関数の仕組みと使用方法について解説します。

shadcn/ui のユーティリティ関数 cn()

以下が cn() 関数の実装コードです。 この関数は、clsxtailwind-merge の 2 つのライブラリを組み合わせて実装されています。

lib/utils.tsx
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

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

インポート

まず、clsxtailwind-merge の 2 つのライブラリをインポートしています。

  • clsx: 条件付きでクラス名を結合するためのライブラリです。オブジェクトのキーが true と評価される場合、そのキーがクラス名として結合されます。
  • tailwind-merge: Tailwind CSS のクラス名の競合を解決するためのライブラリです。複数のクラス名が競合する場合、正しいクラス名を選択して返します。

cn() 関数

cn() 関数は、可変長引数 (...inputs) を受け取り、それらを clsx() 関数に渡してクラス名を結合します。 次に、その結果を twMerge() 関数に渡してクラス名の競合を解決します。

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

使用例

以下は、cn() 関数の使用例です。

import { cn } from "./lib/utils";

function ExampleComponent({ isActive }) {
  return (
    <div
      className={cn("base-class", isActive && "active-class", "another-class")}
    >
      Example
    </div>
  );
}
React TSX

この例では、isActivetrue の場合にのみ active-class がクラス名として追加されます。 また、twMerge がクラス名の競合を解決します。

clsx()

clsx() は、条件付きでクラス名を結合するための関数です。 渡された値のうち、0false"" といった偽と評価される要素は無視し、それ以外を 1 つの文字列に結合します。

import { clsx, type ClassValue } from "clsx";

// Strings (可変長引数)
clsx("foo", true && "bar", "baz");
//=> "foo bar baz"

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

// Objects (可変長引数)
clsx({ foo: true }, { bar: false }, null, { "--foobar": "hello" });
//=> "foo --foobar"

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

// 入れ子の Arrays (可変長引数)
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"
TypeScript

twMerge()

Tailwind CSS でスタイリングする際に、同じ要素に対して複数のクラス名が適用される場合、競合が発生することがあります。 twMerge() 関数は、このような競合を解決し、最終的に適用されるクラス名を決定します。

import { twMerge } from "tailwind-merge";

const className = twMerge("bg-red-500", "bg-blue-500");
// => "bg-blue-500"
React TSX

競合するクラスは最後に指定されたクラスが優先されます。 この例では、bg-red-500bg-blue-500 の両方が指定されていますが、twMerge は最後に指定された bg-blue-500 を適用します。

コメント

コメントする