svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Svelte does not handle external CSS imports correctly when compiling components as custom elements (Web Components)

Open GCastilho opened this issue 10 months ago • 1 comments

Describe the bug

If a component is exported as a custom element using

<svelte:options customElement="some-component" />

any foreign CSS imports that works in normal Svelte componentes don't work on the custom element:

  • Using

    import './custom.css';
    

    works as expected in regular Svelte components, but when used in a custom element, the styles are not properly scoped or injected into the shadow root.

  • Adding a stylesheet with

    <svelte:head>
      <link rel="stylesheet" href="/custom.css" />
    </svelte:head>
    

    causes Svelte to insert the <link> into the document's <head>, not into the custom element's shadow root. This means the styles are global and not encapsulated within the custom element, which causes them to not affect it at all (see AquaCounter for a manual workaround).

  • Importing CSS via a <style> tag:

    <style>
      @import "./custom.css";
    </style>
    

    partially works, but if the imported CSS contains selectors not used in the component's markup, Svelte emits a 'css-unused-selector' warning. Additionally, the imported CSS is scoped only to the current component and is not available to child components, so it cannot act as a "global" style for the custom element.

Reproduction

I've created a repository to demonstrate the bug and some workarounds one can use to import foreign CSSs

https://github.com/GCastilho/svelte-css-imports-custom-elements-bug-demo

Instructions and details are on README

Logs

N/A

System Info

System:
    OS: Windows 11 10.0.26100
    CPU: (14) x64 Intel(R) Core(TM) Ultra 5 135U
    Memory: 3.91 GB / 15.52 GB
  Binaries:
    Node: 22.16.0 - C:\Program Files\nodejs\node.EXE
    pnpm: 10.11.1 - C:\Program Files\nodejs\pnpm.CMD
  Browsers:
    Edge: Chromium (134.0.3124.85)
  npmPackages:
    svelte: ^5.28.1 => 5.33.14

Severity

blocking all usage of svelte

GCastilho avatar Jun 11 '25 13:06 GCastilho

I've created a preprocessor to workaround this issue (global CSS only). It's hacky but it get the job done

https://gist.github.com/GCastilho/edf7c6a96b6bfa8e9dabb58b3e88931f

GCastilho avatar Jun 13 '25 16:06 GCastilho

Besides being highly interested in this, I think its also worth noting that even when using the component <style> Svelte fails to HMR the Shadow DOM component properly. The DOM updates if the HTML template is updated, but the styles aren't.

MrVauxs avatar Jul 08 '25 09:07 MrVauxs