Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Svelte dynamic html elements do not have css applied

Tags:

svelte

I have a svelte component which uses a library to display JSON tree, but that library needs an html hook where to be loaded. Afterwards it generates it's own html structure with it's own classes and ids. So far so good, but if I add inside my component some styles for the selectors which are generated in future, the style is not applied.

Is this the problem ? Is there some work around ?

Here is my code example:

<script>
  import { onMount } from "svelte";
  import { Content } from "@smui/card";
  import { copyToClipboard } from "../../public/js/utils";

  export let data;
  let contentBody;

  onMount(() => {

    const editor = new JSONEditor(
      contentBody,
      { mode: "view", navigationBar: false },
      data
    );

    const editorMenu = document.getElementsByClassName("jsoneditor-menu")[0];
    const copy = document.createElement("img");
    copy.src = "../../public/img/copy.png";
    copy.setAttribute("class", "custom-button");
    editorMenu.append(copy);

    copy.onclick = () => copyToClipboard(editor.getText()));
  });
</script>

<style>
  .jsoneditor-menu {
    background-color: #525b69;
    border: 1px solid #e8e8e8;
  }

  .jsoneditor {
    border: 1px solid #e8e8e8;
  }

  .json {
    height: 555px;
  }

 .custom-button {
    width: 20px;
    height: 20px;
    margin: 2px;
    padding: 2px;
    border-radius: 2px;
    border: 1px solid transparent;
    color: #fff;
    opacity: 0.8;
    font-family: arial, sans-serif;
    font-size: 10pt;
    float: left;
  }

</style>

<Content>
  <div class="json" bind:this={contentBody} />
</Content>

Note: The style is applied only for root element json class

like image 866
V. Sambor Avatar asked Jan 09 '20 17:01

V. Sambor


1 Answers

Yes, you've correctly identified the problem. The solution is to make your style global with the :global magic pseudo selector (docs).

<style>
  /* this will not be removed, and not scoped to the component */
  :global(.foo) { ... }

  /* this will not be removed, but still scoped to divs inside _this_ component */
  div :global(.bar) { ... }
</style>

CSS scoping in Svelte is implemented by adding a unique class to the CSS selectors as you've authored them. For example if you write .foo, the compiler will turn it into .svelte-a3bmb2.foo.

For this to work, the compiler also need to add this class to all the elements that matches the selector .foo. It can do that for the elements it sees in the markup. But it can't do it for elements that are dynamically created at runtime.

That's why (I guess) Svelte removes CSS rules that matches nothing in the component's markup. The compiler normally issue warnings when it does that, something like "unused CSS selector".

If you make the styles global, the compiler doesn't need to scope them anymore, so problem solved.

like image 150
rixo Avatar answered Nov 11 '22 11:11

rixo