Join my Laravel for REST API's course on Udemy 👀

Component template should contain exactly one root element in Vue.js

April 20, 2022  ‐ 2 min read

Since Vue version 3 your template can contain multiple root elements. That is, inside the <template> part of a Vue component you can have multiple HTML elements at the root. See the example below:

<template>
  <h1>This works in Vue 3</h1>
  <p>This is a second root element.</p>
</template>

However, if you are working in a Vue 2 codebase you will the following error when trying the code above:

Component template should contain exactly one root element.
If you are using v-if on multiple elements,
use v-else-if to chain them instead.

Use a single root element

In this case you should move the two root elements in your template to a single wrapper element. For example, lets wrap the above in a single <div> element.

<template>
  <div>
    <!-- This is now the root element  -->
    <h1>This works in Vue 2 as well</h1>
    <p>This is not a root element anymore</p>
  </div>
</template>

With conditionals

The error message does hint on the fact that the problem could be caused by unchained conditional directives; using multiple v-if's instead of chaining them with a v-else and/or v-else-if.

Lets consider the following example:

<template>
  <h1 v-if="loading">Page is loading</h1>
  <h1 v-if="error && !loading">Whoops an error occurred</h1>
  <h1 v-if="!error && !loading">Success!</h1>
</template>

Since using just v-if's on your root elements you could potentially end up in a situation were multiple conditions evaluate to true. Which would result in multiple root elements, which Vue 2 cannot properly deal with. Giving the error:

Errors compiling template:

Component template should contain exactly one root element.
If you are using v-if on multiple elements,
use v-else-if to chain them instead.

1  |
2  |  <h1 v-if="loading">Page is loading</h1>
   |
3  |  <h1 v-if="error && !loading">Whoops an error occurred</h1>
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4  |  <h1 v-if="!error && !loading">Success!</h1>
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Instead you want to use a v-else-if and a v-else here. Which would look like the following:

<template>
  <h1 v-if="loading">Page is loading</h1>
  <h1 v-else-if="error && !loading">Whoops an error occurred</h1>
  <h1 v-else>Success!</h1>
</template>