Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

:global(...) not working in custom elements #2969

Closed
dylanblokhuis opened this issue Jun 7, 2019 · 15 comments · Fixed by #8457
Closed

:global(...) not working in custom elements #2969

dylanblokhuis opened this issue Jun 7, 2019 · 15 comments · Fixed by #8457

Comments

@dylanblokhuis
Copy link

Whenever you use the :global() modifier in custom elements the css output will still contain the modifier.

To reproduce the issue you can use this repo: dylanblokhuis/svelte-global-modifier-issue

@itswillta
Copy link

I was trying to build some custom elements with Svelte and encountered the same issue.

I have found out that :global() currently doesn't work with custom elements. When the customElement option is enabled, Svelte deliberately doesn't transform your style in any sort of way (well, except for removing the "unused selectors").

@constgen
Copy link

constgen commented Jun 8, 2019

Native Web Components styles are isolated by the spec, aren't they? May be that's why Svelte doesn't process their styles as they are applied only to a component by the platform itself.

@s0kil
Copy link

s0kil commented Jun 10, 2019

:global() doesn't get processed at all.
Screenshot from 2019-06-10 12-17-21

@dylanblokhuis
Copy link
Author

Until this is fixed you can use svelte-preprocess. the modifier does get compiled when using this

@JohnRSim
Copy link

Until this is fixed you can use svelte-preprocess. the modifier does get compiled when using this

I tried to use preprocess on a custom element but couldn't get it to work using :global(...
Had a look through your other projects encase you had any examples but didn't see anything in the rollup-config.

@LunaTK
Copy link

LunaTK commented Nov 19, 2019

Native Web Components styles are isolated by the spec, aren't they? May be that's why Svelte doesn't process their styles as they are applied only to a component by the platform itself.

I agree.

But in that sense, any selector inside :global should be unwrapped, since :global is meaningless.

However, svelte currently does not touch :global at all, leaving it even after compilation.
Since :global is not standard css spec, any style using :global doesn't work at all.

I think it should at least be unwrapped.

@kmmbvnr
Copy link

kmmbvnr commented Dec 16, 2019

It seems :global style removing happens in the Stylesheet.transform (second arg) And that transformation explicitly disabled for custom elements

https://github.com/sveltejs/svelte/blob/master/src/compiler/compile/render_dom/index.ts#L32

@diegologs
Copy link

Any update on this or at least a workaround?

The idea of ​​using :global is simply to be able to write CSS rules that are not in the component markup. Another solution could be to be able to disable globally the option to delete unused CSS.

Thanks for your work!

@sawden
Copy link

sawden commented Jun 27, 2021

Is there already a solution for global styles with "customElement: true"? 😕

@vospascal
Copy link

vospascal commented Jul 1, 2021

Cant you use :host in custom-elements web components ?

@SergkeiM
Copy link

SergkeiM commented Aug 6, 2021

+1 to this,

Until this is fixed, I used content-replace-webpack-plugin

To replace :global() (used with <style global>)

plugins: [
	new ContentReplacePlugin({
        	rules: {
		      '**/*.js': content => content.replace(/:global\((.*?)\)/g, '$1')
	          }
	})
]

Update: is better to use this regex: /:global\(([\[\]\(\)\-\.\:\*\w]+)\)/g (above was replacing some characters that shoud remain.

Update 2: (Vite)

Can you use vite-plugin-replace

plugins: [
        replaceCodePlugin({
            replacements: [
                {
                    from: /:global\(([\[\]\(\)\-\.\:\*\w]+)\)/g,
                    to: "$1",
                }
            ]
        }),
    ]

Dirty but as temp fix.

@WIStudent
Copy link

I also ran into the issue that svelte kept removing css because it thought it was unused. Instead of using :global I found a different workaround. I moved the css into a separate file and imported it inside the <script> block (I am using vite, it already comes with the necessary loaders).

import css from './App.scss';

Then I used a <svelte:element> to add the css to the shadow-root.

<svelte:element this="style">{@html css}</svelte:element>

This way svelte will not remove "unused" css. See the full example below:

// App.scss
@use "@material/card";
@include card.core-styles;
<!-- App.svelte -->
<script lang="ts">
  import { onMount } from 'svelte';
  import { MDCRipple } from '@material/ripple';
  import logo from './assets/svelte.png';
  import css from './App.scss';

  let primaryAction: HTMLDivElement;

  onMount(() => {
    MDCRipple.attachTo(primaryAction);
  });
</script>

<svelte:options tag="my-card"/>

<svelte:element this="style">{@html css}</svelte:element>
<div class="mdc-card">
  <div
    bind:this={primaryAction}
    class="mdc-card__primary-action"
    tabindex="0"
  >
    <div class="my-card__media mdc-card__media mdc-card__media--16-9" style="background-image: url({logo});"></div>
    <div class="mdc-card__ripple"></div>
  </div>
</div>


<style>
  :host .my-card__media {
    background-size: contain;
  }
</style>

mpellerin42 added a commit to nuclia/frontend that referenced this issue Sep 12, 2022
`:global(…)` doesn't work on custom elements. Here's a workaround suggested in
sveltejs/svelte#2969 (comment)
mpellerin42 added a commit to nuclia/frontend that referenced this issue Sep 12, 2022
`:global(…)` doesn't work on custom elements. Here's a workaround suggested in
sveltejs/svelte#2969 (comment)
@Oreilles
Copy link

It's not just :global though, it seems that the component css isn't processed at all by the preprocessor plugin.
For examle, having this snipped inside a svelte component tagged for web component export:

<style lang="scss">
    @import 'maplibre-gl/dist/maplibre-gl.css';
</style>

This results in the @import being present as is in the style element of the shadow dom.

@anuj-kosambi
Copy link

anuj-kosambi commented Jan 6, 2023

@Oreilles

I don't know this will be correct way to do or not, but I had managed to get workaround by this

  1. compiling differently for web-components and normal svelte components folder
  2. by creating separate two files for single component in web-components and components folder
  3. importing appropriate svelte component in web-component

Example

components/
   normal.svelte
web-components/
   normal.svelte

components/normal.svelte

<svelte:options tag={null} />

<span class=".container">
    <SomeNestedComponent class="nested"/>
</span>

<style>
  .container :global(.nested){
     background: red
  }
</style>

web-components/normal.svelte

<svelte:options tag="normal" />


<script>
import Normal from '../components/normal.svelte'
</script>

<Normal/>

vite.config.js

export default defineConfig({

  build: {

  },
  plugins: [
    svelte({
      include: './src/web-components/*',
      compilerOptions: {
        customElement: true
      }
    }),
    svelte({
      exclude: './src/web-components/*',
      emitCss: false,
      compilerOptions: {
        customElement: false
      }
    }),
    svg(),
  ]
})

dummdidumm added a commit that referenced this issue May 2, 2023
This is an overhaul of custom elements in Svelte. Instead of compiling to a custom element class, the Svelte component class is mostly preserved as-is. Instead a wrapper is introduced which wraps a Svelte component constructor and returns a HTML element constructor. This has a couple of advantages:

- component can be used both as a custom element as well as a regular component. This allows creating one wrapper custom element and using regular Svelte components inside. Fixes #3594, fixes #3128, fixes #4274, fixes #5486, fixes #3422, fixes #2969, helps with sveltejs/kit#4502
- all components are compiled with injected styles (inlined through Javascript), fixes #4274
- the wrapper instantiates the component in `connectedCallback` and disconnects it in `disconnectedCallback` (but only after one tick, because this could be a element move). Mount/destroy works as expected inside, fixes #5989, fixes #8191
- the wrapper forwards `addEventListener` calls to `component.$on`, which allows to listen to custom events, fixes #3119, closes #4142 
- some things are hard to auto-configure, like attribute hyphen preferences or whether or not setting a property should reflect back to the attribute. This is why `<svelte:options customElement={..}>` can also take an object to modify such aspects. This option allows to specify whether setting a prop should be reflected back to the attribute (default `false`), what to use when converting the property to the attribute value and vice versa (through `type`, default `String`, or when `export let prop = false` then `Boolean`), and what the corresponding attribute for the property is (`attribute`, default lowercased prop name). These options are heavily inspired by lit: https://lit.dev/docs/components/properties. Closes #7638, fixes #5705
- adds a `shadowdom` option to control whether or not encapsulate the custom element. Closes #4330, closes #1748 

Breaking changes:
- Wrapped Svelte component now stays as a regular Svelte component (invokeing it like before with `new Component({ target: ..})` won't create a custom element). Its custom element constructor is now a static property named `element` on the class (`Component.element`) and should be regularly invoked through setting it in the html.
- The timing of mount/destroy/update is different. Mount/destroy/updating a prop all happen after a tick, so `shadowRoot.innerHTML` won't immediately reflect the change (Lit does this too). If you rely on it, you need to await a promise
@dummdidumm
Copy link
Member

Closed via #8457, to be released in Svelte 4

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