tailwindcss-scoped-preflight
TypeScript icon, indicating that this package has built-in type declarations

3.4.9 • Public • Published

Tailwind CSS + UI libraries = no conflicts 🚀

NPM Downloads GitHub Repo stars

What

Tailwind CSS plugin

Why

To avoid style conflicts (CSS collisions/interference side effects) when using Tailwind CSS with other UI libraries like Antd, Vuetify etc.

How

This plugin is limiting the scope of Tailwind's opinionated preflight styles to the customizable CSS selector. So you can control where exactly in DOM to apply these base styles - usually it's your own components (not the 3rd party).

Version 3 is here 🎉

Migrate from v2 | Migrate from v1

Looking for old version's documentation? v2 | v1

Starting from version 3 it provides a powerful configuration to (optionally):

  • 🤌 precisely control CSS selectors;
  • 💨 flexibly remove any preflight styles;
  • 🔎 or even modify particular values of the Tailwind preflight styles (if you have some very specific conflicts).

❤️ If you'd like to say thanks, buy me a coffee

Buy Me A Coffee
Support/contact tiny website

Strategies overview

For ease of use, there are 2 pre-bundled isolation strategies available (as named exports) that cover 99% cases:

Pre-bundled strategy Description
isolateInsideOfContainer
inside
Everything is protected from the preflight styles, except specified Tailwind root(s).
Use it when you have all the tailwind-powered stuff isolated under some root container.
isolateOutsideOfContainer
outside
Protects specific root(s) from the preflight styles - Tailwind is everywhere outside.
Use it when you have Tailwind powered stuff everywhere as usual, but you want to exclude some part of the DOM from being affected by the preflight styles.
isolateForComponents (deprecated)
components
It generates the same CSS as isolateInsideOfContainer with small difference about root styles - so I just put it as an option of isolateInsideOfContainer strategy to simplify the strategy selection while still be able to use both modes if needed. If you use this strategy - migrate to isolateInsideOfContainer and set rootStyles to add :where for the same effect).

🔨 If none of these strategies work for your case, or something isn't perfect - you can create your own strategy.

Quick Start

1. Install

npm i -D tailwindcss-scoped-preflight

2. Update your Tailwind CSS configuration

2.1 Case: you want to lock Tailwind preflight styles inside of some root container (or multiple containers), so they couldn't affect the rest of your web page.

Use isolateInsideOfContainer:

// tailwind.config.js

import { scopedPreflightStyles, isolateInsideOfContainer } from 'tailwindcss-scoped-preflight';

/** @type {import("tailwindcss").Config} */
const config = {
  // ...
  plugins: [
    // ...
    scopedPreflightStyles({
      isolationStrategy: isolateInsideOfContainer('.twp', {
        except: '.no-twp', // optional, to exclude some elements under .twp from being preflighted, like external markup
      }),
    }),
  ],
};

exports.default = config;
Option Value Description
except (optional) CSS selector to exclude some elements under .twp from being preflighted, like external markup
rootStyles (optional) move to container (default) moves the root styles to the container styles (by simply replacing the selector)
add :where adds :where to the root selector so styles are still in roots, but only matching items would be affected
remove (optional) array of CSS selectors Removes specified (with CSS selectors) preflight styles
ignore (optional) array of CSS selectors Keeps these preflight selectors untouched (skipped by the isolation strategy)

2.2 Case: you want Tailwind preflight styles to be everywhere except some root container(s) that may collide.

Use isolateOutsideOfContainer:

// tailwind.config.js

import { scopedPreflightStyles, isolateOutsideOfContainer } from 'tailwindcss-scoped-preflight';

/** @type {import("tailwindcss").Config} */
const config = {
  // ...
  plugins: [
    // ...
    scopedPreflightStyles({
      isolationStrategy: isolateOutsideOfContainer('.no-twp', {
        plus: '.twp', // optional, if you have your Tailwind components under .no-twp, you need them to be preflighted
      }),
    }),
  ],
};

exports.default = config;
Option Value Description
plus (optional) CSS selector if you have your Tailwind components under .no-twp, you need them to be preflighted. Specify their root selector with this option
remove (optional) array of CSS selectors Removes specified (with CSS selectors) preflight styles
ignore (optional) array of CSS selectors Keeps these preflight selectors untouched (skipped by the isolation strategy)

3. Use specified selectors in your DOM

export function MyApp({ children }: PropsWithChildren) {
  return <div className={'twp'}>{children}</div>;
}

Configuration examples

Using the strategy for multiple selectors

scopedPreflightStyles({
  isolationStrategy: isolateInsideOfContainer(
-   '.twp',
+   [
+     '.twp',
+     '[twp]',
+   ],
  ),
})

Although all the strategies allow you to specify a number of selectors - it's recommended to use one short selector to avoid CSS bloat as selectors repeat many times in the generated CSS.

Keeping some preflight styles unaffected

scopedPreflightStyles({
  isolationStrategy: isolateInsideOfContainer(
    '.twp',
    // every strategy provides some base options to fine tune the transformation
+   {
+     ignore: ["html", ":host", "*"],
+   },
  ),
})

Removing some preflight styles by CSS selector

scopedPreflightStyles({
  isolationStrategy: isolateInsideOfContainer(
    '.twp',
+   {
+     remove: ["body", ":before", ":after"],
+   },
  ),
})

Your own/custom isolation strategy

isolationStrategy option is basically a function that accepts the original CSS selector and returns the transformed one.

// tailwind.config.js

import { scopedPreflightStyles } from 'tailwindcss-scoped-preflight';

/** @type {import("tailwindcss").Config} */
const config = {
  // ...
  plugins: [
    // ...
    scopedPreflightStyles({
      //it's just a function accepting { ruleSelector: string } and returning modified rule selector (prefixed or whatever you need)
      isolationStrategy: ({ ruleSelector, ...whateverElse }) => {
        // let's say we want to scope the styles for some global selectors Tailwind utilizes:
        if (
          [
            'html',
            ':host',
            'body',
          ].includes(ruleSelector)
        ) {
          return `${ruleSelector} .twp`; // adding the .twp class to these global things so only things under .twp would be affected
        }

        // let's say we want table to be preflighted only when under the .twp
        if (ruleSelector === 'table') {
          return `.twp ${ruleSelector}`;
        }

        // and don't want * to be preflighted at all
        if (ruleSelector === '*') {
          // returning an empty string or anything falsy/nullish removes the CSS rule
          return '';
        }

        // Caution! Don't forget to return the value,
        // falsy/nullish result will remove the rule.
        // Either return the original ruleSelector, or inject some of existing strategies,
        // let's fallback to the isolateInsideOfContainer strategy for this demo:
        return isolateInsideOfContainer('.twp')({ ruleSelector, ...whateverElse });
      },
    }),
  ],
};

exports.default = config;

Modifying the preflight styles

This option allows you to hook into the preflight styles to perform some modifications like removing or changing CSS properties.

You may configure the modifications in a declarative manner (as an object) or provide a function to have more control.

Object syntax

scopedPreflightStyles({
  isolationStrategy: isolateInsideOfContainer('.twp'), // whatever
  modifyPreflightStyles: {
    html: {
      // removes the line-height for the html selector
      'line-height': null,
      // changes the font-family
      'font-family': '"Open Sans", sans-serif',
    },
    body: {
      // replaces the margin value for the body selector in preflight styles
      margin: '0 4px',
      // following won't have any effect as this property is not in the preflight styles
      color: 'red',
    },
  },
});

Function syntax

scopedPreflightStyles({
  isolationStrategy: isolateInsideOfContainer('.twp'), // whatever
  modifyPreflightStyles: ({ selectorSet, property, value }) => {
    // let's say you want to override the font family (no matter what the rule selector is)
    if (property === 'font-family' && value !== 'inherit') {
      return '"Open Sans", sans-serif';
    }
    // or body margin
    if (selectorSet.has('body') && property === 'margin') {
      return '0 4px';
    }
    // if you want to remove some property - return null
    if (selectorSet.has('html') && property === 'line-height') {
      return null;
    }
    // to keep the property as it is - you may return the original value;
    // but returning undefined would have the same effect,
    // so you may just omit such default return
    return value;
  },
});

Migration guide (to v3)

from v2

for 'matched only' mode users

import {
  scopedPreflightStyles,
+ isolateInsideOfContainer,
} from 'tailwindcss-scoped-preflight';

// ...
     scopedPreflightStyles({
-       mode: 'matched only',
-       cssSelector: '.twp',
+       isolationStrategy: isolateInsideOfContainer('.twp'),
      }),

for 'except matched' mode users

import {
  scopedPreflightStyles,
+ isolateOutsideOfContainer,
} from 'tailwindcss-scoped-preflight';

// ...
     scopedPreflightStyles({
-       mode: 'except matched',
-       cssSelector: '.notwp',
+       isolationStrategy: isolateOutsideOfContainer('.notwp'),
      }),

from v1

import {
  scopedPreflightStyles,
+ isolateInsideOfContainer,
} from 'tailwindcss-scoped-preflight';

// ...
     scopedPreflightStyles({
-       preflightSelector: '.twp',
-       disableCorePreflight: true,
+       isolationStrategy: isolateInsideOfContainer('.twp'),
      }),

Package Sidebar

Install

npm i tailwindcss-scoped-preflight

Weekly Downloads

31,933

Version

3.4.9

License

MIT

Unpacked Size

116 kB

Total Files

11

Last publish

Collaborators

  • roman_js