Codekid
Codekid

Reputation: 21

Vue import scss but apply it to slot content

I'm trying to create a theme switcher in Histoire that will allow me to show a component in two different themes.

For this I have two wrapper components that import different scss files (theme files). The wrappers' purpose is to wrap a component and apply that theme file to the component it wraps.

foo.scss

.my-table {
    background-color: blue;
}

bar.scss

.my-table {
    background-color: red;
}

For both these stylesheets I have a wrapper that imports them like this:

WrapperComponent.vue

<template>
    <div id="fooThemeWrapper">
        <slot></slot>
    </div>
</template>

<script lang="ts" setup>

</script>

<style lang="scss" scoped>
@use '../scss/themes/foo';
</style>

The wrapper component is applied to the Histoire variant like this

const fooThemeSetup = defineSetupVue3(({ addWrapper }) => {
    addWrapper(fooThemeWrapper);
});

The issue I'm facing is that the rules from the scss files are not being applied to the slot content.

I tried making the style tag not scoped. This applied the style of both scss files to the slot content but this resulted in one scss file overwriting the other. I want the style imported by the wrapper component to only be applied to the wrapper components slot content.

Is there a way to apply the components scoped identifier (the attribute added to all the scoped components elements) to the components slot content as well?

Upvotes: 0

Views: 193

Answers (1)

Khoa
Khoa

Reputation: 2932

The issue I'm facing is that the rules from the scss files are not being applied to the slot content.

This is because:

With scoped, the parent component's styles will not leak into child components. However, a child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. This is by design so that the parent can style the child root element for layout purposes. - https://vuejs.org/api/sfc-css-features.html#scoped-css

Next:

I tried making the style tag not scoped. This applied the style of both scss files to the slot content but this resulted in one scss file overwriting the other.

Global styles will be bundled so even your component is conditional rendered, it is only "conditional" in rendering, not in bundling. Eventually, it will be packed into a single css file.

And because they are both the same selector, they will cascade.

To build a theming system, you can modify like this:

  1. wrap each theme into data selector. eg:
    [data-theme="foo"] {
        .my-table {
        }
    }
  1. conditional value for data attribute

Assume you can access body tag

<body :data-theme="condition ? 'foo' : 'bar'">
</body>

Notes:

  • <body> tag is just example, they could be <html> tag, and container tags (as long as it is parent of any tags that use my-table class.
  • This is just one approach but quite popular. There are another approach using CSS's variable but it is not closed to your current code base and a bit complex.

Upvotes: 0

Related Questions