Tailwind CSS V4でカスタムプラグインの入れ方がわからなくて一度V3に戻そうとした話

Tailwind CSS V4を使ってたが、カスタムプラグインの入れ方がわからなくて一回V3に戻そうとしたら、今度はV3特有の問題にぶち当たって、結局V4でプラグインのインポート方法を見つけて解決した話。
迷走したおかげで両バージョンの違いも理解できたし、未来の自分(と同じ問題で悩む人)のためにメモしておく。

なぜV4からV3に戻そうとしたのか

CSSだけでスタイリングしたかった

そもそもの発端は、remを使いたいのにいい感じに書けないことでした。

const className = 'text-sm' // どれくらいのサイズかわからん
const className = 'text-[10px]' // これは嫌だ
const className = 'text-[0.625rem]'  // こうしたいけど見づらい
const className = 'text-10px' // こう書いたら font-size: 0.625rem が指定されてほしい

V3だと簡単にできそうやった

V3の場合、tailwind.config.jsで簡単に設定できる。

// tailwind.config.js
theme: {
  fontSize: {
    '10px': '0.625rem'
  }
}

V4だとFunctional utilitiesを使う必要がある

V4の場合はFunctional utilitiesを使う必要があるらしい?

// 動かないよ
@utility text-*px {
  font-size: calc(var(--value, integer) / 16)rem;
}

でも、*には特定のものしか受け付けなさそうで、思ったようにいかない。

カスタムプラグインを作る必要があった

結局カスタムプラグインを作る必要があることがわかったが、V4でのプラグインの入れ方がわからなかった
結果「もうV3に戻すしかないか!」となった。

V3に戻そうとして新たな問題に直面

shadcn/uiのカラーが適切に動かない

V4ではprimary/50とかでテーマカラーのopacity指定がデフォルトで可能なので、shadcn/uiのコンポーネントのカラーが適切に設定されていた。
でもV3では同じ記法が使えないらしい... Claude Codeにすべてを任せた弊害が出た...

primaryの設定自体はうまく行ってるはず。shadcnのテーマを継承している。

theme: {
  extend: {
    colors: {
      primary: {
        DEFAULT: 'var(--primary)',
        foreground: 'var(--primary-foreground)',
      },
    }
  }
}

V3で同様記法を使うためのコツ

調べてみると、V3で同様の記法を使うにはちょっとコツが要るらしい。
新たな学びを得た。

参考Issue

theme: {
  extend: {
    colors: {
      primary: {
        DEFAULT: 'rgb(from var(--primary) r g b / <alpha-value>)',
        foreground: 'rgb(from var(--primary-foreground) r g b / <alpha-value>)',
      },
    }
  }
}

V4でも@pluginでプラグイン入れられるじゃないか!

迷走してる途中で、V4でも@pluginディレクティブでプラグインが入れられることを発見。
カスタムのやつもJSファイルを別で作って入れられるらしい。

なぜかはまったインポート問題

import plugin from 'tailwindcss/plugin'; 
// default exportされてるのか...node_modulesまで型定義見に行かないと参照できなかった...

const customPlugin = plugin(({ addUtilities }) => {
  addUtilities({
    '.test-1px': {
      'margin-top': 'calc(1px)',
    },
  });
});

export default customPlugin; // ここもdefault exportしないといけないみたい

型定義を見るまでdefault exportやって気づかんかった。

最終的な解決方法

結局、V4で以下のような感じでカスタムプラグインを作成して解決。

import plugin from 'tailwindcss/plugin';

const customPlugin = plugin(({ matchUtilities }) => {
  const allowedFontSizes = [10, 11, 12, 13, 14, 15, 16, 18, 20, 24, 28, 32, 40, 48, 56, 64, 128];

  const fontSizeValues = allowedFontSizes.reduce((acc, size) => {
    acc[`${size}px`] = `calc(var(--spacing) / 4 * ${size})`;
    return acc;
  }, {});

  matchUtilities(
    {
      text: value => ({
        fontSize: value,
      }),
    },
    {
      values: fontSizeValues,
    }
  );
});

// biome-ignore lint/style/noDefaultExport: Allow default export for plugin
export default customPlugin;
/* app.css */
@import 'tailwindcss';
@plugin "./fontSizePxToRem.js";

これでtext-10pxtext-24pxみたいに書けるようになった!

学んだこと

V3とV4の違い

  • プラグインシステム: V4の方が柔軟だけど、記法が変わってる
  • カラーシステム: V4はopacity指定がデフォルトで楽
  • 設定ファイル: V3はJS設定、V4はCSS中心

迷走したからこそ得られた知見

  • V3のopacity対応方法
  • V4のプラグインインポート方法
  • default exportの重要性

最初からV4のドキュメントをちゃんと読んでればよかったんやけど、迷走したおかげで両方のバージョンの差異を理解できたのは良かったかもしれない。