tailwindlabs / tailwindcss

A utility-first CSS framework for rapid UI development.
https://tailwindcss.com/
MIT License
82.48k stars 4.17k forks source link

Add tailwind prefix during build #1746

Closed jony1993 closed 4 years ago

jony1993 commented 4 years ago

I currently have a custom Vue component library which uses tailwindcss. To avoid naming collisions with other libs I currently use a custom tailwind prefix.

If I want to use a tailwind UI component I always have to add my prefix manually for all the tailwind classes (so I can't simple copy and paste the code).

So I'm wondering: What's the best strategy to deal with such naming collisions? Is there a way to prefix tailwind classes during build time, to avoid adding prefixes manually all the time?

estevanmaito commented 4 years ago

What if you're using Tailwind and another library that also uses a common class, like .my-4 (Bootstrap, for example).

If you don't prefix before building, how would the build system know what class to prefix?

You could use a tool like VS Code Intellisense to prefix it for you while you develop https://github.com/bradlc/vscode-tailwindcss/issues/104

adamwathan commented 4 years ago

We're going to fix this at the Tailwind UI level by making it possible to add a prefix to the code snippets πŸ‘ No plans for a template processing thing built into Tailwind though I'm afraid.

lnwu commented 2 years ago

what if working in a monorepo codebase, one enable prefix another not, how intellisense will be like?

anburocky3 commented 2 years ago

Yeah right, I'm developing my first UI library and facing the same problem.

Creating the code along with prefix is creating headaches. :/

For example, look at this code:

  let colors =
    'jui-py-2 jui-px-4 jui-font-semibold jui-rounded jui-shadow jui-text-white disabled:jui-opacity-75 disabled:jui-cursor-not-allowed';
  switch (variant) {
    case Variant.PRIMARY:
      colors += ' jui-bg-indigo-500 hover:jui-bg-indigo-600  ';
      break;
    case Variant.SECONDARY:
      colors += ' jui-bg-blue-500 hover:jui-bg-blue-600 ';
      break;
    case Variant.SUCCESS:
      colors += ' jui-bg-green-500 hover:jui-bg-green-600 ';
      break;
    case Variant.DANGER:
      colors += ' jui-bg-red-500 hover:jui-bg-red-600 ';
      break;
    case Variant.WARNING:
      colors += ' jui-bg-orange-500 hover:jui-bg-orange-600 ';
      break;
    case Variant.INFO:
      colors += ' jui-bg-blue-400 hover:jui-bg-blue-500 ';
      break;
    case Variant.DARK:
      colors += ' jui-bg-gray-800 hover:jui-bg-gray-900 jui-text-white';
      break;
    default:
      colors += ' jui-bg-gray-50 hover:jui-bg-gray-100 jui-text-black ';
      break;
  }

Looks little weird and needs to be typed everytime. Sometimes, i forgot why it was not working and later, i figured out that, i didn;t use prefix there. :/

yinkakun commented 1 year ago

Yeah right, I'm developing my first UI library and facing the same problem.

Creating the code along with prefix is creating headaches. :/

For example, look at this code:

  let colors =
    'jui-py-2 jui-px-4 jui-font-semibold jui-rounded jui-shadow jui-text-white disabled:jui-opacity-75 disabled:jui-cursor-not-allowed';
  switch (variant) {
    case Variant.PRIMARY:
      colors += ' jui-bg-indigo-500 hover:jui-bg-indigo-600  ';
      break;
    case Variant.SECONDARY:
      colors += ' jui-bg-blue-500 hover:jui-bg-blue-600 ';
      break;
    case Variant.SUCCESS:
      colors += ' jui-bg-green-500 hover:jui-bg-green-600 ';
      break;
    case Variant.DANGER:
      colors += ' jui-bg-red-500 hover:jui-bg-red-600 ';
      break;
    case Variant.WARNING:
      colors += ' jui-bg-orange-500 hover:jui-bg-orange-600 ';
      break;
    case Variant.INFO:
      colors += ' jui-bg-blue-400 hover:jui-bg-blue-500 ';
      break;
    case Variant.DARK:
      colors += ' jui-bg-gray-800 hover:jui-bg-gray-900 jui-text-white';
      break;
    default:
      colors += ' jui-bg-gray-50 hover:jui-bg-gray-100 jui-text-black ';
      break;
  }

Looks little weird and needs to be typed everytime. Sometimes, i forgot why it was not working and later, i figured out that, i didn;t use prefix there. :/

Hey, I think this library can help in this situation - https://www.npmjs.com/package/postcss-prefix-selector

OneFourFree commented 1 year ago

We're going to fix this at the Tailwind UI level by making it possible to add a prefix to the code snippets πŸ‘ No plans for a template processing thing built into Tailwind though I'm afraid.

Hey, was this ever added to the Tailwind UI site? It's a bit of a pain having to add the prefix every time.

It would be nice if you could add a prefix and color to the settings on the site and have the code snippets dynamically incorporate the settings.

BaptisteCayrier commented 1 year ago

Hi, a while ago vesper8 made an online tool to add prefixes easily: https://github.com/tailwindlabs/discuss/issues/404 The tool is accessible here: https://github.vue.tailwind-prefix.cbass.dev/

Edit: the tool is not working correctly for custom values like bg-black/[0.4] and for classes that next to char "`" like:

classname=`inline-flex`
euan-cowie commented 11 months ago

We're going to fix this at the Tailwind UI level by making it possible to add a prefix to the code snippets πŸ‘ No plans for a template processing thing built into Tailwind though I'm afraid.

@adamwathan Are there still plans for this sometime in the future? Would be very handy for working in monorepo environments for building out design systems. Thanks!

smissingham commented 7 months ago

If you don't prefix before building, how would the build system know what class to prefix?

Adding a use case. I'm a browser extension developer, using Plasmo. We use tailwind to style our options page, and to style injected components. So, it is safe to assume that all uses of tailwind classes within our project are tailwind-only and not some other lib.

After the extension injects tailwind into the web page, only then do we have risk of css class name clashes.

It'd be great if tailwind had a build option to auto-prefix everything at build time to prevent clashes but save us the inconvenience of prefixing everything ourselves

https://docs.plasmo.com/framework/content-scripts-ui/styling#caveats

Deykun commented 4 months ago

I spent some time looking for a solution to this problem and eventually decided to use a Tailwind prefix. It isn't ideal, but autocomplete in VSCode works fine with it (you can type "text-sm" and it will suggest "prefix-text-sm") and is less problematic than alternatives.

If you have a large codebase and want to use Tailwind prefixes, here is something that will help add prefixes to at least some classes (in my project, I solved 95% of the migration with code based on this): https://github.com/tailwindlabs/tailwindcss/discussions/2598#discussioncomment-4813766

If you insist on using unprefixed classes (which I understand, as I've tried to achieve this myself), you can create a PostCSS process to rename your class names. For example:

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    "postcss-prefix-selector": {
      prefix: "prefix-",
      transform: function (prefix, selector, prefixedSelector, filePath) {
        if (!selector) {
          return selector
        }

        if (filePath.includes("@ext")) {
          return selector
        }

        const isClassname = selector.includes(".")

        if (!isClassname) {
          return selector
        }

        const className = selector.replace(".", "")

        return prefixClassname(className, prefix)
      }
    }
  }
}

This converts the generated class names in the CSS file to prefixed ones but has its flaws. If you are using something inside that produces CSS, it will land there too. For example, @storybook classes have been broken because of this, so you have to write a really smart transform function for it, and it’s very easy to break something else.

That fixes the output. To fix the input, you have to wrap all your class names with a wrapper that adds prefixes, e.g., className={cl("text-lg lg:bg-red")}. You don't use the Tailwind prefix option, and "text-lg" is recognised. The cl function should turn that code into "prefix-text-lg lg:prefix-bg-red" to match the code transformed by PostCSS.

Problems with that solution include the first mentioned above: we don't have a 100% guarantee that we transform only Tailwind classes, so we have to validate everything ourselves. Additionally, there is an extra hassle with class names. "hover:text-sm" in cl() should be "hover:prefix-text-sm", but in PostCSS, it should be something like &:hover .prefix-sm (:hover isn't just a name of a class), so we cannot use the same prefixClassName function in cl and postcss.

I wish that the Tailwind team would divide the prefix in the config into prefixIn/prefixOut for people interested, and a expose prefixing for us to use in all classNames={}, but they don't. Prefixing everything is inconvenient, but doing that with PostCSS is problematic, so I chose the inconvenient option.