Find and fix regressions caused by :slotted() in Vue 3

If you’re in the process of upgrading to Vue 3, and noticed missing styles in the content that you put in slots, this is for you. The best solution I’ve found was to use vue-scoped-css/no-unused-selector to find issues automatically and fix them manually.

Breaking change

While upgrading our fairly large application (Learning Management System) to Vue 3, I’ve bumped into a styling issue. As described in Vue RFC 0023-scoped-styles-changes:

Slot content passed in from the parent no longer gets affected by child scoped styles by default. Instead, the child now needs to use the new ::v-slotted() (:slotted() for short) pseudo element to specifically target slot content.

It wasn’t mentioned in the Vue 3 Migration Guide, so I had to notice and analyze visual issues, like a lack of padding. It got me to the Slotted Selectors docs page and the mentioned RFC.

Affected code example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dropdown.vue

<template>
<ul class="dropdown">
<slot>
</ul>
</template>

<style scoped>
// To fix use :slotted(.dropdown__item)
.dropdown__item {
color: red;
}
</style>
1
2
3
4
5
6
7
Menu.vue

<template>
<dropdown>
<li class="dropdown__item">I should use default color</li>
</dropdown>
</template>

Challenge

I’ve found a few places in the app, where styling issues were noticable and fixed them. But that wouldn’t scale. Our LMS is complex enough, and not consistent enough, for it to be a feasible task. We don’t have visual tests, so no help there. I didn’t know how many issues are there or how to find them, other than looking and comparing with Vue 2 version.

ESLint rule

What helped me is vue-scoped-css/no-unused-selector. It reports selectors defined in <style scoped> not used in <template>. It finds .dropdown__item from the example.

It has found 242 problems in our application. Although it wasn’t pleasant to hear, it was much better than not knowing what was broken. As mentioned, we have enough legacy for there to be a lot of false positives, just regular unused styles. The rule also finds missing :deep selectors, which mean bugs or leftovers. I decided it’s better to clean them all up, as I have to investigate anyway. But you could quickly ignore reported files, when there are no slots, or the issue is obviously not slot-related.