core: when i using render function, the scoped style not working

Version

3.0.0-beta.19

Reproduction link

https://codepen.io/bundlejs/pen/abdYYrQ

Steps to reproduce

use templete, the scoped style is right, but use render h(), it`s bad.

What is expected?

use render function,scoped style is working

What is actually happening?

scoped style is not working


"dependencies": {
    "vue": "^3.0.0-beta.19"
  },
"devDependencies": {
  "@vue/compiler-sfc": "^3.0.0-beta.19",
  "less": "^3.11.3",
  "vite": "^1.0.0-beta.11"
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 11
  • Comments: 17 (4 by maintainers)

Most upvoted comments

I ran into the same issue. I wasn’t so much surprised that it wasn’t supported, more so that it seems the data-v-<scopeId> attribute on the nodes were suffixed with -s and removing the suffix was enough to apply the styles. The comment where I think this suffix is being added makes it seem like these nodes are treated as slot content, which is confusing to me. I’m sure I don’t understand the logic scopes completely, so I’m probably missing something, but I guess I would expect CSS scoping of render functions to work rather than narrowly missing (not sure if this is a vue-loader or vue-next change). And yes, the only use case I can think of for render functions in SFCs is <style scoped>; which I think can make sense if most of the code base is SFCs and you have some very dynamic components you want to write as render functions and you also want style scoping but you don’t want to introduce new tooling for CSS Modules.

However, it would also seem reasonable to make it very clear that <style scoped> and render functions don’t work by having vue-loader show a warning if <style scoped> is used without a <template>, since there are other ways to achieve the same goal.

Ran in same issue. It was very useful feature: SFC with render function + scoped style. Is there any plans when it will be implemented in vue3?

What’s the point of using render functions inside single file components?

If people could do it in vue 2 they’ll continue to do so if it makes sense to them, or they’re migrating a vue 2 project

i have same problem: image image

I ran into this same issue. I needed to wrap elements from a slot and there was no way to do it in a normal template, so I had to make a render function. However, that broke all my scoped CSS.

Why in the hell is a “-s” being added to the scope IDs of render function output and how can it be made to stop doing it?

EDIT:

h("div", {[`${this.$options.__scopeId}`]: ""})

I’m not sure if I’m a genius or just insane.

I agree with @aztalbot.

I’d love to keep using SFCs <style scoped> section along with render functions. I have some components which have such dynamic template code (e.g. conditional event listeners and props) that using <template> would probably be a bad decision. Having all the styles encapsulated in the <style> section would keep components consistent and more readable, I think.

For future folks, I’ve solved this with the following “scope patch” where needed:

Using <script setup> in component using a render function:

// e.g. InlineComponent.vue

<script setup lang='ts'>
const scopePatch = { [getCurrentInstance().vnode.scopeId]: '' }
const InlineComponentRoot = () => h('div', { ...scopePatch, /* class: 'blah', etc... */ })
</script>

<template>
  <InlineComponentRoot />
</template>

Example consuming component:

// e.g. Consumer.vue

<template>
  <InlineComponent class='myClass' />
</template>

<style scoped>
.myClass {
  width: 50px;
}
</style>

This properly renders the v-data-* attribute from Consumer.vue on the DOM outputted from the InlineComponent.vue component, and the styles apply as expected. For me, this brought back what I was used to re: behavior from Vue 2.

this problem seems can be solved by using ::v-slotted() pseudo element in scoped style. it’s works for me: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0023-scoped-styles-changes.md

Another possible solution, at least if you’re looking to avoid naming collisions, is to use css modules instead:

https://vuejs.org/api/sfc-css-features.html#css-modules

<script lang="ts" setup>
import { h, useCssModule } from 'vue'

const classes = useCssModule('classes')

function render() {
    return h('div', { class: classes.foo })
}
</script>

<template>
    <render />
</template>

<style module="classes">
.foo {
    color: 'red';
}
</style>

The -s that is being appended in comment is also breaking Scoped CSS on slot content which was fixed to address this issue https://github.com/vuejs/vue-loader/issues/113