📖

Reactで動的にCSSを適用するなら?classNames・clsx・CVA・classcatを比較

2025/03/05に公開

Reactアプリを開発していると、ボタンの状態ごとにクラスを切り替えたり、コンポーネントに適用するスタイルを条件分岐させたりする場面が頻繁に出てきます。例えば、

  • フォームの入力状態に応じてエラースタイルを適用する
  • ボタンがクリック可能かどうかでデザインを変更する
  • テーマやサイズによってスタイルを切り替える

このように、CSSを動的に適用する必要があるケースは多く、className の値を適切に組み立てることが求められます。

ライブラリを使用しない場合の問題点

ライブラリを使用せずにクラス名を動的に切り替える場合、三項演算子を多用することになりコードが冗長になりがちです。

<button
  className={
    isActive ? `${styles.btn} ${styles.active}` : styles.btn
  }
>
  Click
</button>

このようなコードは状態が増えると可読性が低下し、メンテナンスが困難になります。

そこで、本記事では、動的にクラスを適用するためのライブラリ4つ を比較し、それぞれの特徴とおすすめの用途を解説します!


🔍 ライブラリ候補

1. classnames

レポジトリ: JedWatson/classnames

✅ 特徴

  • React公式ドキュメントにも登場する、定番のクラス結合ライブラリ。
  • classNames(styles.btn, { [styles.active]: isActive }) のように、オブジェクト形式で条件付きクラスを適用できる。
  • 古くから使われているため、情報が豊富。

⚠️ デメリット

  • clsx に比べると パフォーマンスがやや劣る
  • バンドルサイズも若干大きめ(gzip後約436B)。

2. clsx

レポジトリ: lukeed/clsx

✅ 特徴

  • classnames軽量・高速な代替ライブラリ
  • APIはほぼ同じで、移行も簡単。
  • && を使ってより簡潔に記述できる。
    import clsx from 'clsx';
    <button className={clsx(styles.btn, isActive && styles.active)}>Click</button>
    
  • バンドルサイズが小さい(gzip後約239B) ので、最適化にも◎。

⚠️ デメリット

  • 特に?

3. class-variance-authority(CVA)

レポジトリ: jorgebucaran/class-variance-authority

✅ 特徴

  • コンポーネントの状態管理が多い場合に便利!
  • variant ごとにクラスを管理できるので、スタイルの整理がしやすい。
  • cva() を使って、クラスロジックを事前定義できる。
    import { cva } from 'class-variance-authority';
    
    const button = cva(styles.btn, {
      variants: {
        variant: {
          primary: styles.primary,
          secondary: styles.secondary,
        },
      },
    });
    
    <button className={button({ variant: 'primary' })}>Click</button>
    
  • 型安全 に管理できるのも大きなメリット。

⚠️ デメリット

  • 最初の学習コストが少し高い(variants の概念を理解する必要あり)。
  • シンプルなケースにはオーバースペックかも。

4. classcat

レポジトリ: jorgebucaran/classcat

✅ 特徴

  • classnames に似ているが、さらに軽量(gzip後約217B)
  • APIが配列ベースなので、少し独特。
    import cc from 'classcat';
    <button className={cc([styles.btn, { [styles.active]: isActive }])}>Click</button>
    
  • 最速クラスのパフォーマンス で、大量レンダリング時にも有利。

⚠️ デメリット

  • classnamesclsx に比べると、やや馴染みが薄い
  • 可変引数でクラスを渡せないので、直感的に書きづらいことも。

🔥 どれを選ぶべき?

ライブラリ バンドルサイズ パフォーマンス 型安全性 おすすめ用途
classnames 436B 普通 なし clsx に移行しない限りそのまま使うのもOK
clsx(おすすめ) 239B 高速 なし シンプルなクラス結合をするならこれで良さそう
CVA 683B 普通 あり コンポーネントの状態ごとにスタイルを管理したいとき
classcat 217B 最速 なし パフォーマンス最優先ならアリ

🏆 結論:基本は clsx でOK、拡張性が必要なら CVA

  • シンプルなクラス結合なら clsx
    • 軽量・高速・書きやすい
  • バリアントごとのスタイル管理が必要なら CVA
    • 状態管理を型安全に管理できる
  • classnames を使っているなら、clsx に移行してもOK

クラスの動的付与をシンプルにして、React開発をもっとスムーズにしましょう!🚀


🔗 参考記事

Discussion