Tailwindで「親要素に特定のクラスがあるときのみ適用される」ユーティリティクラスをつくる


実現したいこと

warm-theme:bg-red-400のように書くことで、親要素に.warm-themeがあるときのみbg-red-400が適用されるようにしたい。こうすると、同じマークアップでスタイルのみを切り替えることができたりする。

<!-- 親要素にwarm-themeがある場合 -->
<div class="warm-theme">
  <div class="bg-blue-300 warm-theme:bg-red-400 w-20 h-20">A</div>
</div>

<!-- 親要素にwarm-themeがない場合 -->
<div>
  <div class="bg-blue-300 warm-theme:bg-red-400 w-20 h-20">B</div>
</div>

環境

TL;DL

tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  variants: {
    extend: {
      backgroundColor: ['warm-theme'],
    },
  },
  plugins: [
    plugin(({ addVariant }) => {
      addVariant('warm-theme', ({ modifySelectors, separator }) => {
        modifySelectors(({ className }) => {
          return `.warm-theme .warm-theme${separator}${className}`
        })
      })
    }),
  ],
}

解説

Tailwindではhorver:bg-red-400とすることで、hover時にのみbg-red-400が適用される。このhover:の部分をvariant と呼ぶ。(参考: https://tailwindcss.com/docs/configuring-variants )
標準では、hoverの他にfocus, activeなどがある。
variantは自分で独自のものを作ることができる。
公式ドキュメントのCreating your configuration fileを参考にすると以下のようにかける

tailwind.config.js
// ...略..
plugin(({ addVariant }) => {
  addVariant('warm-theme', ({ modifySelectors, separator }) => {
    modifySelectors(({ className }) => {
      return `.warm-theme .warm-theme${separator}${className}`
    })
  })
}),
  • classNameはwarm-theme:bg-red-400と書いた場合は、bg-red-400のことを指す。
  • separatorは:のこと。
  • modifySelectorsの部分はwarm-theme:bg-red-400というクラスから.warm-theme .warm-theme:bg-red-400というCSSセレクタを生成する。

上記のconfigにより、一例として以下のようなCSSが生成される。

.warm-theme .warm-theme:bg-red-400 {
  --tw-bg-opacity: 1;
  background-color: rgba(248, 113, 113, var(--tw-bg-opacity));
}

なお、自作したvariantを適用するためには、以下のようにvariants.extendに追加する。

tailwind.config.js
// ...略..
variants: {
  extend: {
    backgroundColor: ['warm-theme'],
  },
},

ちなみにこの状態だと、bg-*のユーティリティクラスにしか使えない。テキストの色でも使いたい場合は、textColor: ['warm-theme']を追加する必要がある。適当にすべてのユーティリティクラスを対象にしてしまうと生成されるCSS量が多くなりすぎるので注意。

最後に

Tailwindプレイグラウンドは、VSCodeライクなエディタで、tailwind.config.jsをいじりながら試せるため非常に便利。
お試しあれ。