Kycha Blog.

How to scope Tailwind CSS rules?

Cover Image for How to scope Tailwind CSS rules?
Andrii Kycha
Andrii Kycha

The other day, I was working on my React Chatbot Widget (GitHub link) and realized there was something I didn't account for. Of course, I needed to scope all the Tailwind CSS classes right from the beginning!

Tailwind CSS

I am not a professional blogger who studies their audience carefully and tailors their articles based on the pragmatic insights gathered from their analytics scripts. I can't assume all of the readers understand what Tailwind is and what scoping is. That's why I'll start from the beginning.

I don't pretend to be an expert in Tailwind CSS or a person who knows everything about front-end development, so take my words with a grain of salt.

Tailwind CSS is a CSS library that allows you to define your component styles directly in your components! Now, there are dozens of ways you can integrate Tailwind CSS into your app written in any framework (or maybe you went Vanilla?). Since I work with React for the most part, I will be presenting examples with React in mind.

Let's go back to 2014, when people defined styles for their apps using good old CSS. Around this time, I got into web development myself.

.article {
  background: red;
}

You all know what will happen when we apply this stylesheet to our document. And if you don't, that's fine; we all learn something new every day. All the elements with the article class name assigned to them will have a red background.

(Interestingly, each browser decides what the red color is for it. Meaning red in Safari can be slightly different from the red in Chrome (definitely not green though lol 🟢). Neat!)

Action 🎮 Let's see how we can style a component the Tailwind way.

<div className="bg-red-600"></div>

Now, what's the difference, you ask? I wouldn't pretend I have an all-in-one answer to this question, but I can tell from experience that it's just slightly easier. You don't need to switch context between working in the .css files and your component files (which can be .jsx or .tsx). You are just in the flow, working on making your component better with every single line of code while working in the same file.

CSS Scoping

Scoping was a big deal when Sass/LESS pre-processors hit the market back in the day. These tools allowed you (and they still do) to nest CSS rules within other CSS rules (inception.jpg). This level of technology had never been seen before. It was magical 🪄

Let me show you an example to wrap your head around this concept.

.article {
  background: red;

  .title {
    font-weight: 500;
  }
}

This tricky construction above adds a red background to all the elements with the article class name. But what it also does is assign font-weight: 500 to every element with the title class name if it's a child of an article element.

So, you would only get a stylish semibold title if you had markup like the one below.

<div className="article">
  <p className="title">Boy, am I cool 😎</p>
</div>

<p className="title">This one is not cool 😢</p>

Why do I need to scope Tailwind Preflight?

Answer: To avoid messing with the existing CSS rules in the app.

Wait, what is Tailwind Preflight?

It's a fancy term for all the CSS rules Tailwind adds to your page that are globally available in each and every React component you have in your codebase.

So, why do I need to scope Tailwind Preflight?

Maybe you are adding Tailwind CSS to a legacy (very old) project and want to use Tailwind only for a small portion of your application.

Maybe you are a genius who created a brand-new library using Tailwind CSS that will conquer the world. When sharing this library with people, you want to ensure your Tailwind-backed app doesn't break the styles in your users' apps.

No way my Tailwind app is going to break my users' apps...

Yeah, it can! And it will, if you don't scope Tailwind Preflight.

When you add Tailwind to your code, you add the following lines to your index.css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

This construction adds all the class names like bg-red-600 to the stylesheet. This stylesheet, in turn, will be injected into the DOM tree where your app is rendered. Simply put, all the Tailwind classes will be added to the page and can (and will 😈) overwrite the existing class names with the same names defined on this page.

Chances are there are already class names like bg-red-600 in your legacy app or in the user-defined stylesheets. Chances are these classes have CSS rules associated with them that are very different from what Tailwind has defined. Guess what? They are gone now!

The full CSS name—Cascading Style Sheet—gives you a hint as to why that happens. If you have two or more class names with specific CSS rules, only the latest one in the stylesheet will be applied!

/* Okay -> 😵 */
.bg-red-600 {
  background: tomato;
}

/* Sorry for overwriting, but I am more important 🤩 */
.bg-red-600 {
  background: red;
}

Scoping Tailwind Preflight

Finally, we are here, ready to find out the secret ingredient that this whole article was built upon.

Step 1: Install tailwindcss/nesting

npm i tailwindcss/nesting

Step 2: Update your postcss.config.js

export default {
  plugins: {
    "tailwindcss/nesting": {},
    tailwindcss: {},
    autoprefixer: {},
  },
};

Step 3: Update your index.css

.react-chatbot-widget {
  @tailwind base;
}

/* The prefix for components and utilities is handled by the "important" setting in the tailwind.config.js file */
@tailwind components;
@tailwind utilities;

Step 4: Update tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  // This will help us prefix the .hover, .active, .focus, etc. Tailwind-generated CSS rules
  important: ".react-chatbot-widget",
  content: ["./src/**/*.{ts,tsx,html}", "./.storybook/**/*.{ts,tsx,html}"],
  plugins: [],
};

Au revoir

You've made it!

In this article, we briefly looked into what Tailwind CSS and CSS scoping are, understood why you might want to scope Tailwind Preflight (and found out what Tailwind Preflight is), and, last but not least, saw how to scope Tailwind Preflight to avoid overwriting existing styles in the app!

See you next time you land on my blog! In the meantime, check out my GitHub profile and see if something catches your interest.

If you want to support me, drop a star on the repository you think deserves it on my GitHub profile!

This is not mandatory, so you don't have to do it. I will continue writing even if you don't. But... this will help me a great deal in building a stronger GitHub profile and landing more opportunities in my software development journey 🚗

Cheers!