CSS @property conflicts when extension uses Tailwind v4 and host page uses Tailwind v3
Describe the bug
When using Shadow Root UI with Tailwind CSS v4, the extension's @property rules conflict with host pages that use Tailwind CSS v3, breaking their gradient styles and other CSS properties.
Root Cause:
WXT's splitShadowRootCss function (introduced in PR #1594) extracts @property rules from shadow DOM CSS and injects them into the host page's <head>. This is necessary because @property doesn't work inside shadow DOM.
However, when the extension uses Tailwind v4 (which defines typed @property rules like syntax: "<color>") and the host page uses Tailwind v3 (which uses composite CSS variable values), conflicts occur:
-
Extension (Tailwind v4):
@property --tw-gradient-from { syntax: "<color>"; inherits: false; initial-value: #0000; } -
Host Page (Tailwind v3):
--tw-gradient-from: rgba(251, 113, 133, 0.8) var(--tw-gradient-from-position);
The browser enforces the <color> type constraint globally, rejecting the host page's composite value that includes var(--tw-gradient-from-position), causing the host page's gradients to break.
Real-world Impact: Sites like https://yesicon.app/ph (and any site using Tailwind v3) have their gradient buttons and other styles broken when our extension is active.
For more sites has the problem, please refer this issue: https://github.com/mengxi-ream/read-frog/issues/643
Suggested Solution
WXT could provide a built-in configuration option to rename custom properties before injecting them into the host page. For example:
createShadowRootUi(ctx, {
name: 'my-ui',
// New option to prevent conflicts
cssPropertyPrefix: 'wxt-', // or extension-specific prefix
// ...
});
This would rename --tw-* properties to --wxt-tw-* (or custom prefix) at the WXT framework level, preventing naming conflicts with host pages.
Current Workaround
We've implemented a PostCSS plugin to rename properties at build time:
- Issue: https://github.com/mengxi-ream/read-frog/issues/643
- Solution PR: https://github.com/mengxi-ream/read-frog/pull/655
While this works, it would be better if WXT handled this internally to:
- Prevent other extension developers from hitting the same issue
- Make shadow root UI safer by default
- Reduce boilerplate configuration for each extension
Reproduction
- Create a WXT extension with Shadow Root UI using Tailwind CSS v4
- Visit a website that uses Tailwind CSS v3 with gradients (e.g., https://yesicon.app/ph)
- Observe the host page's gradient styles are broken with console error: "Invalid property value, expected type '
'"
Expected behavior: Extension's CSS should not interfere with host page styles.
Steps to reproduce
any WXT extension with shadow root ui can trigger the bug
System Info
System:
OS: macOS 26.0.1
CPU: (14) arm64 Apple M4 Pro
Memory: 315.22 MB / 24.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.10.0 - /Users/leonz/Github/ghost/read-frog-ghost/node_modules/.bin/node
npm: 10.9.3 - /Users/leonz/Library/pnpm/npm
pnpm: 10.16.1 - /opt/homebrew/bin/pnpm
Deno: 2.3.1 - /Users/leonz/.deno/bin/deno
Browsers:
Brave Browser: 140.1.82.166
Chrome: 141.0.7390.123
Firefox: 142.0
Safari: 26.0.1
npmPackages:
wxt: 0.20.10 => 0.20.10
- WXT version: (any version with PR #1594 merged)
- Framework: Tailwind CSS v4
- Conflict occurs with: Any host page using Tailwind CSS v3
Used Package Manager
pnpm
Validations
- [x] Read the Contributing Guidelines.
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [x] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [x] The provided reproduction is a minimal reproducible example of the bug.
I agree this would be good for WXT to handle! We should prefix the property names with the extension ID, so multiple WXT extensions don't conflict with each other.
I agree this would be good for WXT to handle! We should prefix the property names with the extension ID, so multiple WXT extensions don't conflict with each other.
I wanna implement this issue ,could you assign to me? @aklinker1