📖
Reactで動的にCSSを適用するなら?classNames・clsx・CVA・classcatを比較
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>
- 最速クラスのパフォーマンス で、大量レンダリング時にも有利。
⚠️ デメリット
-
classnames
やclsx
に比べると、やや馴染みが薄い。 - 可変引数でクラスを渡せないので、直感的に書きづらいことも。
🔥 どれを選ぶべき?
ライブラリ | バンドルサイズ | パフォーマンス | 型安全性 | おすすめ用途 |
---|---|---|---|---|
classnames | 436B | 普通 | なし |
clsx に移行しない限りそのまま使うのもOK |
clsx(おすすめ) | 239B | 高速 | なし | シンプルなクラス結合をするならこれで良さそう |
CVA | 683B | 普通 | あり | コンポーネントの状態ごとにスタイルを管理したいとき |
classcat | 217B | 最速 | なし | パフォーマンス最優先ならアリ |
clsx
でOK、拡張性が必要なら CVA
🏆 結論:基本は -
シンプルなクラス結合なら
clsx
- 軽量・高速・書きやすい
-
バリアントごとのスタイル管理が必要なら
CVA
- 状態管理を型安全に管理できる
- 今
classnames
を使っているなら、clsx
に移行してもOK
クラスの動的付与をシンプルにして、React開発をもっとスムーズにしましょう!🚀
Discussion