This is a quick and dirty simple method to allow dynamic scoping in Tailwind CSS. It happens on-the-fly thanks to the JIT engine and doesn't need any new config when you want to add a new scope.
Generate this
.admin .scope-\[\.admin\|bg-red-500\+underline\] {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
text-decoration: underline;
}
with this
<div class="scope-[.admin|bg-red-500+underline]"></div>
Well, in some platforms like WordPress, with the new editor Gutenberg, we are encouraged to re-use the markup in the frontend and backend for the dynamic live preview. To keep our views as DRY as possible, we shouldn't need to add logic to conditionally attach different CSS classes in the admin or the frontend.
Another use case is to customize some styles depending on their parent. For example, your card component should have a different text size when it's included in an accordion, but not when it's used in a blog list. That way, your card component stays aware of its possible contexts without the need to create specific overriding classes.
Since it's so simple (barely a few lines in tailwind.config.js), it doesn't really deserve its own Tailwind plugin package and will probably make my tailwindcss-group-variants obsolete.
See it in action here: https://play.tailwindcss.com/7ZR7xajPor
module.exports = {
mode: 'jit',
theme: {
extend: {},
},
variants: {},
plugins: [
/* Tailwind JIT Dynamic Scoping - Add this part to your plugins array */
({ matchUtilities }) => {
matchUtilities({
scope: (value) => {
// We need an arbitrary split character to receive the selector
let split = value.split('|')
// Spaces aren't allowed by JIT's regexes, we use + instead
let rules = split[1].split('+')
return {
[`${split[0]} &`]: {
// JIT engine compiles @apply rules dynamically
[`@apply ${rules.join(' ')}`]: '',
},
}
},
})
}
/* End Tailwind JIT Dynamic Scoping */
],
}
<div class="frontend">
<div class="bg-purple-900 scope-[.admin|bg-red-500+underline] p-12 m-12">
<div class="text-white">
This card has a purple background in the frontend.
</div>
</div>
</div>
<div class="admin">
<div class="bg-purple-900 scope-[.admin|bg-red-500+underline] p-12 m-12">
<div class="text-white">
This card has a red background and underlined text in the backend even if they both have the same markup.
</div>
</div>
</div>
.m-12 {
margin: 3rem;
}
.bg-purple-900 {
--tw-bg-opacity: 1;
background-color: rgb(88 28 135 / var(--tw-bg-opacity));
}
.p-12 {
padding: 3rem;
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.admin .scope-\[\.admin\|bg-red-500\+underline\] {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
text-decoration: underline;
}