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>