0
votes

I am using Svelte/Sapper templae and added Attractions UI, but I cannot apply any class/styles to their custom components, like so:

<TextField class='search-box' type='search' />
<style>
    .search-box {
        margin-bottom: 10px;
    }
</style>

I get

Unused CSS selector ".search-box"

The only way to make it work so far for me was to apply the :global modifier on the style.

2

2 Answers

2
votes

The problem here is that Svelte has no way of knowing that the class property refers to a CSS class here or even where to apply this class. Something to not forget is that the following are all valid Svelte components:

<span>Hello World</span>
<span>Hello</span>
<span>World</span>
Hello World

In the first example, it should probably be on the span, but where should the class go in the second example, the first or second span ? Or maybe both ? And what about the last example where there is no DOM element at all, you cannot add a class to a textnode.

Because of this your class is marked as unused by Svelte and removed during compilation. This is inline with Svelte Single File Component philosophy where all styling for a component is included in the same file. While your construction is counter to that it is sometimes a valid approach, this is what the :global is for.

Note that you can export a class property from TextField and apply to the element of your choice, you would still need to mark the class as global though:

<script>
    // You have to this because class is a reserved keyword in JavaScript
    let className;
    export { className as class };
</script>
<div>
  <p>
    <span class={className}>...</span>
  <p>
  <button>...</button>
</div>
2
votes

I believe what you are trying to achieve is not currently possible in Svelte. The class prop is not treated as special in Svelte, so it does not leak the style scope into the child component, especially since there does not have to be one root element in the child component (unlike in Vue.js, for instance).

Therefore, you cannot add styles in the parent component and expect them to reach the child component. Your only option is to use the :global modifier or add the styles to a global stylesheet (included directly in the HTML, not in a Svelte component)

Note that you can combine :global and scoped styles. For example, consider:

<div class='local'>
    <TextField class='search-box' type='search' />
</div>

<style>
    .local :global(.search-box) {
        margin-bottom: 10px;
    }
</style>

This way, the styles are not leaked to other components and are still scoped to this component only.