radix-ui / themes

Radix Themes is an open-source component library optimized for fast development, easy maintenance, and accessibility. Maintained by @workos.
https://radix-ui.com/themes
MIT License
5.58k stars 201 forks source link

CSS specificity issues w/ tailwind #109

Closed kevinmitch14 closed 1 year ago

kevinmitch14 commented 1 year ago

I recently updated to v2 of Radix Themes and noticed that some of my styles were now being overridden by Tailwind.

Notes: This is only in prod deployments via Vercel, styles are applied correctly when locally developing

My setup was as follows:

// layout.tsx
import "@/app/globals.css"; // Generic tailwind globals.css setup
import "@radix-ui/themes/styles.css";
...

When doing this, the tailwind base styles were taking priority over my radix themes styling. Both specificity (0,1,0).

Screenshot 2023-10-03 at 13 27 06

After playing around with some things, I have tried the following and now the styles are being applied correctly again.

/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "@radix-ui/themes/styles.css";
...

To be honest I am not sure if this is the best option, but it has worked for me and may help others. It would be good to get some advice on this and best practices!

3den commented 1 year ago

I am having the same problem, but moving the import to the the css file made no difference to me.

vladmoroz commented 1 year ago

Those styles are a part of @tailwind base.

Import Radix Themes after @tailwind base and before other Tailwind styles.

@tailwind base;

@import "@radix-ui/themes";

@tailwind components;
@tailwind utilities;
kevinmitch14 commented 1 year ago

I'm aware of the problem so I opened this issue as a note for others. The behaviour is tricky because styles work as expected when developing locally. But when you push to prod, styles don't work.

It is not clear in the docs and I suspect that a lot of people will run into this same issue.

Import the global CSS file at the root of your application. import '@radix-ui/themes/styles.css';

This code snippet does not suggest anything about importing in the CSS file.

Happy to create a PR for the docs site

3den commented 1 year ago

Changing the order of imports on the css file did not work for me, It worked only if i changed the order of imports in the layout.tsx (moving '@radix-ui/themes/styles.css' after all other css imports), but even that was not consistent and broke on prod.

vladmoroz commented 1 year ago

It is not clear in the docs and I suspect that a lot of people will run into this same issue.

Good call, we'll work out a guide on using Radix Themes with Tailwind.

We recently discovered that Next.js doesn’t always bundle css in the order you import it, so this might be a related factor too.

Changing the order of imports on the css file did not work for me

@3den not sure how this could be the case, could you double check with the example I mentioned above? If that still doesn't work, we'd need a repro sandbox to look into.

3den commented 1 year ago

I have moved the radix import after everything.

import '@/styles/app.css';
import '@/styles/overrides.css';
import "@radix-ui/themes/styles.css";

That worked on localhost, but not on prod. It could be that next.js is not obeying the imports order. But even when it does this raises an other issue, having radix imports after tailwind will give it a higher specificity, forcing me to use ! prefix in a lot of classes that did not need it before.

3den commented 1 year ago

@vladmoroz after updating to next ^13.5.4 it breaks even on localhost, does not matter that order are the inputs...

vladmoroz commented 1 year ago

@3den you need to import Radix Themes styles inside a CSS file right after @tailwind base

3den commented 1 year ago

@vladmoroz yes, I did that first, but It did not work.

3den commented 1 year ago

With this css:

@tailwind base;

@import 'react-quill/dist/quill.snow.css';
@import '@radix-ui/themes/styles.css';

@tailwind components;
@tailwind utilities;

Still does not work, and I get this style:

Screenshot 2023-10-04 at 9 19 22 AM
3den commented 1 year ago

I even tried moving each part to its own css file like this index.css:

/* Resets & Variables */
@import './base.css';

/* Dependencies */
@import 'react-quill/dist/quill.snow.css';
@import '@radix-ui/themes/styles.css';

/* Components */
@import './components.css';
@import './overrides.css';

What seems to happen is that next is splitting the css, into multiple files and for some reason the radix one is being loaded before tailwind, no matter what I do. On the code I shared before the imports where moved to before any other rules @tailwind base included.

I'm trying to figure out how to disable next.js code splitting, which will likely solve this problem, but that feels hacky... IMO forcing the specificity to be lower than 011 is overkill, it was already very easy to override radix classes with important configs.

masoudbydesign commented 1 year ago

We're having the same problem over here!

3den commented 1 year ago

@vladmoroz actually seems like @radix-ui css is aways slit to its own file:

Screenshot 2023-10-04 at 10 25 26 AM
vladmoroz commented 1 year ago

OK, I started with a clean Next 13 setup and reproduced this.

Here's the solution I found.

  1. Install postcss-import and add it to your postcss.config.js.
    module.exports = {
    plugins: {
      "postcss-import": {},
      tailwindcss: {},
      autoprefixer: {},
    },
    };
  2. Import Tailwind base via an @import statement in your CSS file, then Radix Themes after:

    @import "tailwindcss/base";
    @import "@radix-ui/themes/styles.css";
    
    @tailwind components;
    @tailwind utilities;

Here it is altogether:

Screenshot 2023-10-04 at 19 28 20

Can you confirm whether this works for you?

3den commented 1 year ago

@vladmoroz works perfectly!!! 🥳 🎉 🍾

Thanks so much for the help 🍻

tyuen commented 11 months ago

// layout.tsx import "@/app/globals.css"; // Generic tailwind globals.css setup import "@radix-ui/themes/styles.css";

I find that the order of these files in either order will cause problems.

Using the AlertDialog as an example:

   <AlertDialog.Root>
      <AlertDialog.Trigger>Learn more</AlertDialog.Trigger>

      <AlertDialog.Content>
        <AlertDialog.Description>Contact support?</AlertDialog.Description>

        <div className="flex justify-center gap-2">

          <AlertDialog.Action>
            <Button className="bg-indigo-500">
            OK
            </Button>
          </AlertDialog.Action>

          <AlertDialog.Cancel>
            <Button>
            Cancel
            </Button>
          </AlertDialog.Cancel>

        </div>
      </AlertDialog.Content>
    </AlertDialog.Root>

if we do this:

import "@/app/globals.css"; // tailwind
import "@radix-ui/themes/styles.css";

Radix will override Tailwind and the OK button above will lose the Indigo color and show the theme color. This prevents me from overriding innate styles.

If we do this:

import "@radix-ui/themes/styles.css";
import "@/app/globals.css"; // tailwind

Tailwind will override Radix and the OK button above will be Indigo as intended, but now the Cancel button will lose the theme color and be overridden by Tailwind's base css.

My workaround is, in the layout.tsx file I'm importing the Radix css second (to override Tailwind's base css) and then I'm using Tailwind's selector strategy which prefixes all Tailwind utility classes with "#tw" so that they override Radix's classes. (Only utility classes will get prefixed, the base classes won't.) I also need to set the id of the body tag to "tw". <body id="tw">

apstone commented 10 months ago

OK, I started with a clean Next 13 setup and reproduced this.

Here's the solution I found.

1. Install `postcss-import` and add it to your `postcss.config.js`.
module.exports = {
  plugins: {
    "postcss-import": {},
    tailwindcss: {},
    autoprefixer: {},
  },
};
2. Import Tailwind base via an `@import` statement in your CSS file, then Radix Themes after:
@import "tailwindcss/base";
@import "@radix-ui/themes/styles.css";

@tailwind components;
@tailwind utilities;

Here it is altogether:

Screenshot 2023-10-04 at 19 28 20

Can you confirm whether this works for you?

This also fixed the issue for me - thanks so much.

kylemh commented 6 months ago

@vladmoroz just thought you might want to know about Next 14.2

We updated how CSS is optimized during production Next.js builds by chunking CSS to avoid conflicting styles when you navigate between pages. The order and merging of CSS chunks are now defined by the import order.

vladmoroz commented 6 months ago

@kylemh oh nice, thanks for surfacing it!

lengoctus commented 4 months ago

Hi you guys. For my solution. I wrapped the Theme component outside of all the components.

  1. Setting index.css:

    image
  2. Setting index.tsx: image

The result:

image

raine commented 1 week ago

In Next 14.2.14, this:

@import "tailwindcss/base";
@import "@radix-ui/themes/styles.css";

gives:

(2:1) postcss-import: @import must precede all other statements (besides @charset or empty @layer)

Import trace for requested module:
./app/globals.css.webpack[javascript/auto]!=!../node_modules/.pnpm/next@14.2.14_@opentelemetry+api@1.9.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[12].use[2]!../node_modules/.pnpm/next@14.2.14_@opentelemetry+api@1.9.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[12].use[3]!./app/globals.css
./app/globals.css

It doesn't happen if the imports are the other way around.