Why are style tags not allowed in a Vue template, but are allowed in a .vue file?

Viewed 2371

I couldn't find it referenced in the documentation, but Vue seems to automatically strip out <style> tags in your template. For example if you have your component in a .js file like...

export default {
   template: (
      `<section>
         <style scoped>
            header { color: blue; }
         </style>
         <header>Hello!</header>
         ...
      </section>`
   ),
   // data, methods, etc.
};

...then your header will not be blue; the style will disappear with the warning "Tags with side effect (<script> and <style>) are ignored in client component templates."

Yet if you are using a .vue file and the vue cli, you are generally encouraged to have three sections - <style scoped> for your CSS, <script> for your JavaScript, and <template> for your HTML template.

Unless there is some other (undocumented?) way to set the style via a component's config parameters, there are two different paradigms - one for a component in js and one for vue components. Why is this? Is there another way for non-vue-cli users to get component-scoped styles into their vue app?

3 Answers

It may be too late to give you a solution, but I think it's not too late for others who may encounter the same problem.

You can work around the problem by using Vue's tag, like this:

<component is="style" scoped>
    .pager.inactive {
        display: none;
    }
</component>

It will at least work for the tag. may be problematic. In addition, I don't know if loading an external CSS file would work. Personally, I would avoid doing that because if your component become to big that you need a separate CSS file, you probably should break down your component into multiple smaller component.

The reason is that there are two different paths for rendering the content, pre-compiled, and run-time-compiled.

When you're using the CLI to compile the SFCs (Single File Component, or .vue file) the compiler will generate the appropriate css file(s) as needed. It will also convert the content of the template into JavaScript code, so the HTML template code is compiled out, and the rendering is handled through the generated js bundle.

On the other hand if you're relying on vue to run-time compile your template, then the compiling of css is not supported for several reasons, such as requiring additional dependencies and not being able to generate a css file, which would make injecting css ambiguous.

If you want to be able to inject css into the page though, there's nothing preventing you from injecting the css manually. You could do this by defining a <template> (or other tag) that would hold the style, and then you can have the component inject a scoping id before each selector and then inject the script into the html. It's not an out-of-the-box solution, and may need some work to reliably handle all selectors, but it's possible.

The Short Answer:

"Templates have compile-time optimizations."

Reference

The Longer Answer:

"While Vue's declarative rendering model abstracts away most of the direct DOM operations for you, there may still be cases where we need direct access to the underlying DOM elements. To achieve this, we can use the special ref attribute:"

<input ref="input">

"ref is a special attribute, similar to the key attribute discussed in the v-for chapter. It allows us to obtain a direct reference to a specific DOM element or child component instance after it's mounted. This may be useful when you want to, for example, programmatically focus an input on component mount, or initialize a 3rd party library on an element."

Reading a bit on the Vue forums I found this too

Aug '19 vue-loader (and Vue template compiler Vue.compile(..) 14) both will filter out any tags that is encounters.

A simple solution to get around this, is to take advantage of Vue’s built-in component

API v2 Reference

Related