-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Description
What version of Tailwind CSS are you using?
v4.1.17
What build tool (or framework if it abstracts the build tool) are you using?
Rolldown-Vite 7.2.2
What version of Node.js are you using?
v22.14.0
What browser are you using?
N/A (affects CSS generation, not browser-specific)
What operating system are you using?
Linux
Reproduction URL
https://github.com/felipenario/tailwind-issue-repo
Describe your issue
When using --opacity-*: initial in the @theme block to clear the opacity namespace (as documented for disabling default utilities), the opacity-related utilities continue to accept bare values like opacity-50, opacity-75, etc.
@import "tailwindcss";
@theme {
/* This should disable default opacity utilities */
--opacity-*: initial;
}<!-- These classes should NOT work but they do -->
<div class="opacity-50">This works but shouldn't</div>
<div class="opacity-75">This works but shouldn't</div>
<div class="backdrop-opacity-50">This works but shouldn't</div>This behavior is inconsistent with other utilities like spacing, which correctly respect the namespace clearing mechanism.
Comparison with spacing utility (working correctly):
@theme {
--spacing-*: initial;
}<!-- These classes correctly DON'T work -->
<div class="p-4">❌ Doesn't generate</div>
<div class="m-8">❌ Doesn't generate</div>Root Cause
After investigating the source code in packages/tailwindcss/src/utilities.ts, I found that:
spacing utility checks if theme exists (~line 567):
values: theme.get(['--spacing']) ? DEFAULT_SPACING_SUGGESTIONS : []opacity utility doesn't check (~line 4997):
handleBareValue: ({ value }) => {
// Missing: if (!theme.get(['--opacity'])) return null
if (!isValidOpacityValue(value)) return null
return `${value}%`
},The spacing utility verifies the theme namespace exists before accepting bare values, while opacity and backdrop-opacity always accept bare values regardless of theme configuration.
Possible Fix
Add theme existence checks to match the behavior of other utilities:
For opacity (lines ~4994-5010):
functionalUtility('opacity', {
themeKeys: ['--opacity'],
handleBareValue: ({ value }) => {
+ if (!theme.get(['--opacity'])) return null
if (!isValidOpacityValue(value)) return null
return `${value}%`
},
handle: (value) => [decl('opacity', value)],
})
suggest('opacity', () => [
{
- values: Array.from({ length: 21 }, (_, i) => `${i * 5}`),
+ values: theme.get(['--opacity']) ? Array.from({ length: 21 }, (_, i) => `${i * 5}`) : [],
valueThemeKeys: ['--opacity'],
},
])This fix was tested and it worked locally
Question
Is this inconsistency intentional, or should opacity utilities behave the same way as other utilities when their theme namespace is cleared with --namespace-*: initial?