-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conflicting className precedence rules #1010
Comments
It's expected behavior. This is how html and css works, you can't change the precedence in html with the order of class-names. What matters is the specificity of css selectors and the order of declarations in the source code if the specificity is the same. Because these declarations have the same specificity (single class-names) and the If you are trying to dynamically toggle between |
@tlgreg got it, thanks for the in depth answer |
The order of class names defined on an HTML element have no effect on styling. CSS Specificity only cares about what is defined in stylesheets. Most specificity articles, including the ones referenced above, don't talk about the order of HTML class names. This helped: As a workaround, I've defined some base styles in order to increase specificity in my tailwind.css: @tailwind base;
body {
@apply text-sm;
}
nav a {
@apply px-3;
@apply py-2;
@apply text-gray-800;
}
nav a.active {
@apply rounded-sm;
@apply bg-blue-gray-dark;
@apply text-gray-200;
}
@tailwind components;
@tailwind utilities; |
It would be interesting to make something like https://www.npmjs.com/package/classnames, but that removes |
I agree with @DylanVann. If tailwindcss used the "latest" class as the most specific, it would make it easier to create reusable components with a fallback class. For example:
Wouldn't this be possible by selectively removing properties from the final class output when there are conflicts? |
You can do something like |
Agreed! I also thought I could create a default styling for a component and override it by simply passing const StatusBadge = ({ status, className }) => {
return (
<span className={`${className} px-4 py-2 ml-auto text-base rounded-full text-yellow-600 bg-yellow-200 `}> {status}</span>
);
}
const App = () => {
return (
// text-base overrides text-sm both like this and when ${className} is at the end
<StatusBadge className='text-sm/> // text appears large
)
} |
For what it's worth, here's a js function I wrote that does this. Later classes are given absolute priority.
Usage:
Notes: The This doesn't work in properties that are semantically grouped towards the front (like I haven't needed the version that handles
Same usage. In reality, you probably need a manual switch to differentiate. |
Nice solution @sirrobert, but classes like I found this more complicated solution that seems to do the trick even for the above problem: https://github.com/richardgill/tailwind-override |
|
By swaping the used class for the border instead of trusting in the order they are defined. In previous version "border-secondary" was defined before "border-white" which seems to not be longer true in the new version. Anyway, see [1][2] and [3] for better understanding of the problem and CSS specificity. [1] tailwindlabs/tailwindcss#1010 (comment) [2] https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity [3] https://css-tricks.com/specifics-on-css-specificity/
By swaping the used class for the border instead of trusting in the order they are defined. In previous version "border-secondary" was defined before "border-white" which seems to not be longer true in the new version. Anyway, see [1][2] and [3] for better understanding of the problem and CSS specificity. [1] tailwindlabs/tailwindcss#1010 (comment) [2] https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity [3] https://css-tricks.com/specifics-on-css-specificity/
You could use the fact that the closest parent takes precedence to create a fallback hierarchy. Wrap the element in a Before: export const P = ({ className, children, ...props }) => (
<p className={`font-sans text-black-500 text-base md:text-lg ${className || ""}`} {...props}>
{children}
</p>
); Fixed: export const P = ({ className, children, ...props }) => (
<div className="font-sans text-black-500 text-base md:text-lg">
<p className={className} {...props}>
{children}
</p>
</div>
); |
In a perfect world, you could write a function that first takes a string of tailwind classes and turns it into CSS. Then secondly, takes that CSS, ignoring and purging all the duplicated and conflicting styles, and turns it back into tailwind classes. Input: const class = tw("text-red-500 p-4", "p-0");
// css: { color: rgb(239 68 68); padding: 1rem; padding: 0rem; }
// purged: { color: rgb(239 68 68); padding: 0rem; }
// result: text-red-500 py-0 |
I found this the package tailwind-merge seems to be what people are looking for. |
Thanks bro this works very well |
Given
which has a conflicting className:
p-4
andp-0
Expected
The button should have a padding of 0, following the CSS rules, i.e. the one that's defined later takes precedence.
Actual
The button has a padding of 4 (
p-4
is taking effect).Side notes
Interestingly, if I swap the class name position from Chrome devtools, i.e.
The button still has a padding of 4.
Is this the expected behavior?
The text was updated successfully, but these errors were encountered: