0

In the process of learning Vue and I'm wondering about some behavior I've come across. I have my primary markup in place and found a use case for making part of the markup a component. However when I add the component to the container with the rest of the markup (which isn't a component) this markup is removed and just the component markup remains. Is this a feature?

<div id="container">
  <Component />
  
  <div class="some-html">
    ...
  </div>
</div>

Once the app is mounted the <div class="some-html"> is removed. In my case this markup will eventually become a component, but for prototyping I was hoping I could mix components with non-components. My current workaround is to wrap the component in a <div>.

Edit This instance is using single file components, run through webpack. Using the suggestion in the answer I removed the mount function while using a self-closing tag on the component. This is what the markup looked like (Badge is the name of the component): markup example

<div class="row"> is a sibling to the component:

markup example two

danparm
  • 25
  • 6

1 Answers1

1

tl:dr

When using in-DOM temlates, do not use self-closing tags. Instead of <component /> use <component></component>

Explanation

This is just a hunch but by the clues given I would say you are using in-DOM template. You are authoring the template directly in index.html - Vue use as a template everything you put inside the element you are mounting to - #container in this case

Problem with in-DOM templates is that the browser parses the HTML before any JavaScript is executed and enforces any rules defined by HTML specification.

Some of them are explained in Vue docs - DOM Template Parsing Caveats

The one not explained there but IMHO causing problem described is that in HTML5 spec, self closing tags are allowed only on "void" elements (Void elements are those that may not ever contain any content - as br, img etc.) - see this SO question - Are (non-void) self-closing tags valid in HTML5?

The result is that your template is presented to Vue like this:

<div id="container">
  <component>
    <div class="some-html">
      ...
    </div>
  </component>
</div>

You can easily check this by commenting out $mount('#container') call, loading the page in the browser and inspecting the page...

And because your Component does not use default slot, everything inside <component> is not rendered at all...

tony19
  • 125,647
  • 18
  • 229
  • 307
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • We are using single file components in this instance, run through webpack. Thought I tried using the non-self closing method but I guess not. Switching to `` did the trick. I'll try disabling the mount function just to verify the behavior but what you described makes total sense here. Thanks @Michal – danparm Jul 12 '21 at 15:55
  • Well that sounds strange - self-closing tags are allowed and even recommended in SFC - https://vuejs.org/v2/style-guide/#Self-closing-components-strongly-recommended – Michal Levý Jul 12 '21 at 15:57
  • What @michal said was exactly correct. Using the self-closing tag caused the component to wrap the sibling markup – danparm Jul 12 '21 at 15:59
  • FWIW this app is using Vue v3, they have the same recommendation in the v3 style guide: https://v3.vuejs.org/style-guide/#self-closing-components-strongly-recommended – danparm Jul 12 '21 at 16:09
  • Could the difference here be the component is used in a child of the root element? If I'm using a component in a component shouldn't the self-closing tag work as intended? – danparm Jul 12 '21 at 16:10
  • 1
    Whether the `Component` is SFC or not doesn't matter. Important thing is where and how it is used. From your edit I would say the `Component` is SFC but it is used directly inside the HTML file (otherwise you wouldn't be able to inspect the markup after commenting out `mount()`) ...and that is the problem – Michal Levý Jul 12 '21 at 16:20