Skip to content

Static CSS option for defineContentScript, CSS scoping for content scripts #2395

Description

@RicBent

Feature Request

CSS scoping between global and shadow DOM UIs can be a bit of an headache currently. As quick solution to at least allow defining CSS for both of these scopes I have the following feature request:

When using content scripts with cssInjectionMode: 'ui' injecting additional global CSS currently requires dynamic addition for example via:

const exampleCssUrl = browser.runtime.getURL('/example.css');
document.head.insertAdjacentHTML('beforeend', `<link rel="stylesheet" href="${exampleCssUrl}">`);

This works, but could be solved more cleanly by directly inserting paths to required CSS into the generated manifest via an option to defineContentScript, for example like this:

export default defineContentScript({
    matches: ['<all_urls>'],
    cssInjectionMode: 'ui',
    cssStatic: ['example.css'],

    async main(ctx) {
        const exampleCssUrl = browser.runtime.getURL('/example.css');
        document.head.insertAdjacentHTML('beforeend', `<link rel="stylesheet" href="${exampleCssUrl}">`);

        const ui = await createShadowRootUi(ctx, {
            name: '<name>',
            position: 'inline',
            anchor: 'body',
            onMount(container) {
                // Create UI with scoped CSS
            },
        });
        ui.mount();
});

Hooking build:manifestGenerated to add CSS paths to content scripts works for production builds, but this sadly does not work for development as content scripts do not use the manifest data there.

This could also be implemented for scripts, but this would not allow any new use-cases.


In general it would be nice if there was a system to scope CSS in content scripts. Vite sadly doesn't provide a system we could (ab)use for this as far as I can tell. My only idea would be something along the lines of inserting markers into the built CSS to allow build-time separation into different scopes.

Basically something like the following:

import 'wxt/scoped-css/reset';          // generates following CSS into /content-scripts/<name>/content.css
import 'wxt/scoped-css/<scope>';         // generates into /content-scripts/<name>/<scope>.css
import 'wxt/scoped-css/all';            // generates into /content-scripts/<name>/*.css

import 'wxt/scoped-css/push/<scope>';   // switch to pushed scope
import 'wxt/scoped-css/pop';            // pop scope

A custom vite plugin would then intercept those imports and replace them with CSS markers we can use for separation of the built CSS. This could work similarly to how the separation of font-family CSS from shadow DOM CSS is done (but at build time I guess).

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions