Skip to content

Conversation

@taiiiyang
Copy link

Overview

Add cssPropertyRename option to createShadowRootUi that allows renaming CSS custom property prefixes to prevent
conflicts with host page styles.

Problem:
When extensions use Tailwind CSS v4 with Shadow Root UI, the @property rules (e.g., @property --tw-gradient-from { syntax: "<color>"; }) are extracted and injected into the host page's <head>. This causes conflicts with host pages
using Tailwind CSS v3, which use composite CSS variable values that don't match the typed syntax constraint.

Solution:

  • Added renameCssCustomProperties() utility function that renames:
    • @property rules: @property --tw-xxx@property --wxt-tw-xxx
    • Property declarations: --tw-xxx: value--wxt-tw-xxx: value
    • var() references: var(--tw-xxx)var(--wxt-tw-xxx)
  • Added cssPropertyRename option to ShadowRootContentScriptUiOptions
  • Both fromPrefix and toPrefix are optional:
    • If only toPrefix is provided: prepends prefix to all custom properties
    • If only fromPrefix is provided: removes the matching prefix
    • If both are provided: replaces fromPrefix with toPrefix

Manual Testing

  1. Create a WXT extension with Shadow Root UI using Tailwind CSS v4:
createShadowRootUi(ctx, {
  name: 'my-ui',
  cssPropertyRename: {
    fromPrefix: '--tw-',
    toPrefix: '--my-ext-tw-',
  },
  onMount(container) {
    // ...
  },
});
  1. Build the extension and load it in the browser
  2. Visit a website using Tailwind CSS v3 with gradients (e.g., https://yesicon.app/ph)
  3. Verify that the host page's gradient styles are NOT broken
  4. Verify that the extension's styles work correctly

Related Issue

This PR closes #1955

@netlify
Copy link

netlify bot commented Dec 17, 2025

Deploy Preview for creative-fairy-df92c4 failed.

Name Link
🔨 Latest commit 629ac25
🔍 Latest deploy log https://app.netlify.com/projects/creative-fairy-df92c4/deploys/6942b693ccbbc20008398cea

Copy link
Member

@aklinker1 aklinker1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good, thanks for writing tests.

We had really bad performance with the splitShadowRootCss function that some else found and improved. Since that function and this new one both are apart of the same function, createShadowRootUi, and slow performance here is known to cause a bad UX, can you benchmark the createShadowRootUi function using real CSS from tailwind?

Compare how many times per second createShadowRootUi can run with or without cssPropertyRename. If it's slow, try and optimize it. If it's fast and the hit is negligable, no need to make any improvements.

You can use Vitest's bench utils to write the benchmark, please include it in the PR, don't just delete it after writing it.

Comment on lines +236 to +237
const css = `.class { --tw-prop: value; }`;
const expected = `.class { prop: value; }`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is... probably fine? Trying to decide if throwing an error would be better than producing this CSS. Probably not? This isn't valid CSS but having weird styles is better than not showing your UI at all? Hmm, not sure. Did you consider throwing an error in this case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think would be a better way to handle the situation when toPrefix or fromPrefix is empty? Maybe we could set both toPrefix and fromPrefix as required fields? If either of them is not passed in, no processing would be done?

Copy link
Member

@aklinker1 aklinker1 Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think there are three options:

  1. Throw an error and make devs look in the console to figure out why their content script UI isn't showing up
  2. Use what you have now and devs will see the UI, but things like borders and rings that depend on custom properties will be styled wrong and they have to debug why it's not showing up correctly.
  3. Don't change the CSS at all if there are invalid options and devs will never know their styles mess up tailwind V3 sites unless they are developing on one directly.

Now that I've written all that out... I think option 1 where we throw an error would be the best DX. It's clear something is broken because their UI wouldn't show up and we can clearly state the problem and solution in the error message without the dev having to go through the CSS and debug which properties are the cause of the bad styles.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I also think option 1 is excellent.

shadowHost: HTMLElement,
) => TMounted;
/**
* Rename CSS custom property prefixes to prevent conflicts with host page styles.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Rename CSS custom property prefixes to prevent conflicts with host page styles.
* Rename CSS custom property and var prefixes to prevent conflicts with host page styles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSS @property conflicts when extension uses Tailwind v4 and host page uses Tailwind v3

2 participants