Open
Description
What problem does this feature solve?
Often when I'm writing scoped CSS for my components I need to put a class on the root element so that I can style it. For example:
<template>
<div class="foo-root">Hello World</div>
</template>
<style scoped>
.foo-root {
color: red
}
</style>
What does the proposed API look like?
CSS already supports a :root
selector which means the "root HTML element of the document" (i.e. usually the <html>
element).
As far as I know it's never possible for a component to be the root <html>
element of the document. So this :root
selector effectively does nothing inside scoped CSS.
Therefore, why not repurpose it to mean the component's root element? We could then re-write the example above without needing to add a specific class:
<template>
<div>Hello, World</div>
<template>
<style scoped>
:root {
color: red;
}
</style>
Admittedly a small idea, but one that I think would save a fair bit of typing (and inventing class names)!
Activity
bpolaszek commentedon Dec 19, 2019
+1024 for this one!
adi518 commentedon Mar 15, 2020
I had this in mind as well, good idea.
jfbrennan commentedon Apr 13, 2020
Guys
:root
really means<html>
and that meaning is very much cemented. Vue shouldn't mess around with that.:host
is closer to what you're looking for and it's what Riot.js uses for this same use case, so support for that in Vue would be much appreciated!jfbrennan commentedon Apr 13, 2020
...come to think of it, the solution can be as simple as:
Maybe this is what a lot of people already do?
davidhewitt commentedon Apr 13, 2020
:host
seems like a better alternative to the:root
I originally proposed!davidhewitt commentedon Apr 13, 2020
Or to think of it... how about
$el
?If that's valid CSS syntax - would be really natural to use given
$el
is already how we access the component's element inside<script>
...bpolaszek commentedon Apr 19, 2020
I just tried it, and it doesn't work.
Besides, this assumes you have a knowledge of the first element being a
div
, meaning this could not applied to this::host
or:root
appear like more generic solutions.bpolaszek commentedon Apr 20, 2020
@davidhewitt In my opinion:
:host
looks semantically like a new concept, it sounds like "we couldn't use :root so we had to find another term".$el
doesn't look CSS at all.As you pointed out,
:root
means "root HTML element of the document" (i.e. usually the element) - so it totally makes sense in a scoped context.@jfbrennan
:root
doesn't necessarily mean<html>
, according to MDN:Perfectly fine in our case IMHO.
jonaskuske commentedon Apr 22, 2020
:host
is a normal CSS pseudo-class though, and it is absolutely appropriate here since Vue’s component syntax is loosely modeled after the [Web Component] spec.True.
What about this sounds "Perfectly fine"? 😅 The definition you yourself have quoted states:
"In HTML, :root represents the element and is identical to the selector html"
Yes,
:root
doesn't necessarily meanhtml
because it can be used in SVG documents, too – but this is quite clear-cut, usage in HTML →html
selector → impractical for the proposed usage as Vue component root.davidhewitt commentedon Apr 22, 2020
FWIW, if anyone's feeling passionate about pushing this forward and has a spare evening, it would probably be a great time to write a Vue 3 RFC on this feature. Especially inspiration could be drawn from vuejs/rfcs#119
(I'm too busy on other projects at the moment or I might have considered writing the RFC myself)
bpolaszek commentedon Apr 22, 2020
My bad, I should have googled more 😅I definitely thought it was an invention of some framework to do the trick we wanted to copy/paste. I go back on my word then,
:host
sounds better indeed 🙂giftkugel commentedon Jun 24, 2020
Is this issue stalled?
I would like to upvote the
:host
suggestion. Why? because it is necessary to select the root element of a component without using anid
orclass
attribute. I think it is important for re-useable components.Example structure
Setting a style for the outer
div
cannot be accomplished withdiv:frist-child
(as suggested in this thread) because it would also match the innerdiv
.Using a CSS class with scoped context leads to a HTML document which is not nice when the component is used
When someone now uses my component
and adds a CSS class called "foo"
the generated HTML looks like
I just want to use styles inside my component for my root element without weird CSS usage.
So I would love to use
Which then should lead to
when used as described above.
rightaway commentedon May 16, 2021
Was RFC created for this?
MattiasMartens commentedon Feb 1, 2022
Curious about this too! Maybe someone in the know could update this with the current best practice (if any)? If no feature has been added to provide even an oblique solution then perhaps there should be an RFC.
bpolaszek commentedon Feb 1, 2022
Something that just complicates everything is that from Vue 3 on, a
<template>
can legitimately host multiple children 😃patarapolw commentedon Apr 20, 2022
Nonetheless
:host > :first-child
or:host > nav
should be a valid selector.pecknigel commentedon Jun 19, 2023
Not seeing how that changes or complicates this.
ByScripts commentedon Mar 7, 2024
I think this would add confusion if we need to use
:host
for a single-root component and:host > :first-child
for a multi-root component.In my opinion,
:host
should match any "root" element of the component.In this example, both
div
should have a border.If you want to style only the first one:
jcupps commentedon Apr 30, 2025
:scope
could be another option, which would seem to align with intended usage: https://developer.mozilla.org/en-US/docs/Web/CSS/:scopevzakharov commentedon May 7, 2025
There are already cases where it leads to edge cases, e.g. warning messages if you try to apply non-prop attrs to no-single-root components. The same warning-message approach can be used here.
What's the usual process for PR'ing here? I don't think it's a huge change and I can try implement it, but I don't know if I need an RFC or something.
jcupps commentedon May 7, 2025
I'm assuming any change to vue-loader to support this would also have to be made to vite at the same time.