tailwindlabs / tailwindcss

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

Important modifier doesn't work on `@apply` rules for custom utilities and components #13102

Open MichaelAllenWarner opened 8 months ago

MichaelAllenWarner commented 8 months ago

What version of Tailwind CSS are you using?

v3.4.1

What build tool (or framework if it abstracts the build tool) are you using?

N/A

What version of Node.js are you using?

v19.8.1

What browser are you using?

Chrome

What operating system are you using?

macOS

Reproduction URL

https://play.tailwindcss.com/N1pmDRsMmo

Describe your issue

This may be intended behavior—if so, apologies for filing this as an issue. I couldn't find any previous discussions or issues about this, though.

The important-modifier doesn't work for @apply rules that are part of custom utilities or components. For example, if I've done:

@layer utilities {
  .foo {
    @apply text-lg underline;
  }
}

then class="!foo" will apply the text-lg and underline rules but without the !important syntax. The same limitation is true if I instead use addUtilities() or addComponents() in my Tailwind config, like:

addUtilities({
  '.foo': {
    '@apply text-lg underline': ''
  }
})

On the other hand, any rules for .foo declared with normal CSS syntax (or normal CSS-in-JS syntax) will get !important in the class="!foo" case.

It would be nice if the important-modifier worked with @apply rules in custom utilities and components. The !important would of course have to go on the actual property-value pairs, which are sometimes nested in at-rules or media queries (with syntax like @apply sm:underline); I don't know whether that would present a major challenge.

In anticipation of the argument that one simply shouldn't use @apply in this way:

In my opinion, this sort of situation—building new utilities/components from existing ones—is precisely where @apply really shines! This technique lets you keep everything "in sync," so that if, for example, the definition of text-lg ever changes, then that change cascades to .foo in my code above. (And you'll even get an error if you try to @apply something that doesn't exist, which I'd argue is helpful here.) I know that one can use the theme() directive to refer to theme-values, but that doesn't let you do things like weave in custom variants with complex selectors (my typical use-cases for this technique are considerably more complicated than the simple example I've given).

1RV34 commented 7 months ago

I have this same issue.

I do think this is simply a missing feature, not a bug. But it definitely is a feature I would like to request!

Input:

@layer components {
  .dev {
    @apply border border-dashed border-red-600;
  }
}
<div class="!dev">...</div>

Output I wish to have:

.\!dev {
  border-width: 1px !important;
  border-style: dashed !important;
  --tw-border-opacity: 1 !important;
  border-color: rgb(220 38 38 / var(--tw-border-opacity)) !important
}

@MichaelAllenWarner unrelated to this feature request / bug, I see you were @applying to the utilities layer. I believe this layer is intended for custom utilities. I think the @layer you should use is components. The tailwind docs seem to demonstrate it very nicely on this page: https://tailwindcss.com/docs/functions-and-directives#layer

MichaelAllenWarner commented 7 months ago

@1RV34

@MichaelAllenWarner unrelated to this feature request / bug, I see you were @applying to the utilities layer. I believe this layer is intended for custom utilities. I think the @layer you should use is components. The tailwind docs seem to demonstrate it very nicely on this page: https://tailwindcss.com/docs/functions-and-directives#layer

Yes, probably (and thank you), and to be clear: the "bug" / feature-request affects both utilities and components. (I just picked one for demonstration purposes.)

That said, here is another aside: I rarely use @layer components or addComponents(), and the reason is that Tailwind "components" don't respect the important preference in the Tailwind config, as described here. Usually this doesn't matter, but I've run into difficulty when using the selector strategy for the purpose of scoping my Tailwind rules. (The prefix option is an alternative, but if you haven't configured it from the beginning then you'll be in for a lot of refactoring.)