👻

TailwindCSSは動的にクラス名を生成できない

2024/12/05に公開

背景

こないだハッカソンに出た時に、state と三項演算子を用いて、動的にクラスを適用しようとしたところ、何故かスタイルがあたらない現象が発生しました。
調べたところ、Tailwind CSS は動的クラスに対応してないとのこと。

Tailwind CSS が動的クラスに対応していない理由

Tailwind CSS はユーティリティクラスベースの CSS フレームワークであり、コンパイル時に使用されるクラスを解析して必要なスタイルだけを生成します。しかし、クラスが動的に設定されている場合、コンパイラがそのクラスを認識できず、結果としてスタイルが適用されない問題が発生します。たとえば、以下のような場合です。

const buttonClass = isActive ? "green-500" : "red-500";
return <button className={`bg-${buttonClass}`}>Click me</button>;

Tailwind CSS で動的スタイルを扱う方法

  1. 関数を使用してスタイルを管理
    JavaScript や TypeScript の関数を利用して動的クラスを生成します。

    const getColorClass = (isActive: boolean) => {
      return isActive ? "bg-green-500" : "bg-red-500";
    };
    
    const DynamicButton: React.FC<{ isActive: boolean }> = ({ isActive }) => {
      return (
        <button className={`p-2 text-white ${getColorClass(isActive)}`}>
          Click Me
        </button>
      );
    };
    

    メリット:

    • Tailwind のクラスをそのまま使用可能。
    • 簡単で柔軟。

    デメリット:

    • 複雑な動的スタイルには対応しづらい。

  1. Tailwind Merge と Tailwind Variant を活用
     
    基本的にはこれが最適解になると思います。
     

    • Tailwind Merge: twMergeを使用して複数のクラスをマージし、重複や優先順位の問題を解決します。
    • Tailwind Variant: tvを使用して動的なバリアント(変化するクラス)を管理します。
    import { twMerge } from "tailwind-merge";
    import { tv } from "tailwind-variant";
    
    const customClass = tv({
      base: "p-4",
      variants: {
        vertical: {
          true: "ml-4 mr-4",
          false: "mt-4",
        },
      },
    });
    
    const ExampleComponent = ({ vertical, classNameProps }) => {
      return (
        <div className={twMerge(customClass({ vertical }), classNameProps)}>
          <p>Content</p>
        </div>
      );
    };
    

    メリット:

    • Tailwind のクラスと完全互換。
    • 複雑なスタイルを整理しやすい。

    デメリット:

    • ライブラリの学習コストがかかる。

妥協案

  1. CSS-in-JS ライブラリを使用
    Tailwind CSS と相性の良い CSS-in-JS ライブラリを使用してスタイルを動的に設定します。例として、styled-componentsemotionを用いる方法があります。

    const Button = styled.button`
      background-color: ${(props) => (props.isActive ? "green" : "red")};
      color: white;
      padding: 0.5rem;
    `;
    
    return <Button isActive={isActive}>Click Me</Button>;
    

    メリット:

    • クラス名の競合を回避できる。
    • 動的スタイルを自由に記述可能。

    デメリット:

    • なら最初から Tailwind 使う必要なし。

  1. Just-In-Time (JIT) モードを使用
    JIT モードは動的クラスの解析をある程度サポートします。ただし、安定版でない場合やセットアップが複雑になることがあります。

    <button className={`bg-${isActive ? "green" : "red"}-500 text-white p-2`}>
      Click Me
    </button>
    

    メリット:

    • 動的クラスの柔軟性をある程度確保。
    • Tailwind のセットアップをほぼ維持。

    デメリット:

    • 非安定版だし、記事も少ない。

  1. styleタグを使用
    Tailwind を使わずにインラインスタイルやカスタム CSS でスタイルを設定します。

    const style = {
      backgroundColor: isActive ? "green" : "red",
      color: "white",
      padding: "0.5rem",
    };
    
    return <button style={style}>Click Me</button>;
    

    メリット:

    • 簡単に動的スタイルを設定可能。

    デメリット:

    • なら最初から Tailwind 使う必要なし。
    • 再利用性が低い。

結論

Tailwind CSS で動的クラスを扱う場合、Tailwind MergeTailwind Variantが推奨されます。
 
 
 
 
以上です。

Discussion