tailwind-merge とは
Tailwind CSSのクラス名を複数引数に与えた時、衝突しないように結合してくれるライブラリです。
Utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
import { twMerge } from 'tailwind-merge' twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]') // → 'hover:bg-dark-red p-3 bg-[#B91C1C]'
便利ですね。
上の例では px-2 py-1 + p-3 のとき p-3 のみが残っていることがわかります。
あとから指定されたpaddingによって上書きされているようです。
直感的です。
なぞ
twMerge('border-solid border-dashed') の結果はどうなるでしょうか。
どちらも border-style の指定ですよね。言うまでもありませんが border-dashed になります。
twMerge('border-solid border-black') は?
border-solid border-black です。色とスタイルなので衝突しませんね。
twMerge('border-[0] border-[blue]') は?
border-[0] border-[blue] です。幅と色なので衝突しませんね。
twMerge('border-[dashed_1px_blue] border-[black]') は?
すこし悩ましいです。答えは border-[black] です。
twMerge('border-t-[blue] border-x-[red] border-[green]') は?
全て色指定です。これをそのままクラスに指定すると上底は青🟦、左辺・右辺は赤🟥、底辺は緑🟩になります。
ですが、twMergeを経由すると border-[green] が残り、全ての辺が緑🟩になります。気をつけないといけませんね。
border は色、スタイル、幅という3つの要素から構成されます。
どのようにして border- のあとが色なのか、スタイルなのか幅なのかを判定しているのでしょうか。
コードを読んで理解する
ライブラリの本体は src/lib ディレクトリ以下に配置されているようです。
src/index.ts から辿り、 src/lib/create-tailwind-merge.ts にたどり着くと、 twJoin してクラスを結合して、 mergeClassList しているようです。
twJoin では、単純にクラス名をスペース区切りの単一な文字列にしている模様。
mergeClassList では、クラス名を1つずつに切り出し、それぞれをパースし、グループID取得、グループIDの衝突があれば除外...というように処理がされているようです。
グループIDの分類は createTailwindMerge に渡した設定を元に処理されます。
デフォルトの設定で一定適切に分類されるようになっており、以下のような判定にマッチするか確認された上でグループIDが割り振られると言った形です。 border- から始まり、 scaleLineStyle にマッチしたらそれは border-style のグループだとなるわけですね。
より厳密な重複判定がしたい場合、独自に設定をすることで可能になるということのようです。
おわり
tailwind-mergeの中身をのぞいてみました。
clsx などと一緒に扱われるライブラリですが、その実態はかなりしっかりとしたロジックを持ち、バンドルサイズを詰めたいケースなどではオーバーすぎるようにも見えます。
ライブラリ導入にはそれに見合うコストが払えるかに気をつけましょう。