Creating Multi-root Vue.js Components
Tags: vue, javascript
Published: 2018-05-22 21:12:31

---
title: Creating Multi-root Vue.js Components
published: true
tags: vue, javascript
canonical_url: https://zendev.com/2018/05/07/multi-root-vue-components.html
---

A common constraint in component-based frameworks like Vue.js is that each component has to have a single root element. This means that everything in a particular component has to descend from a single element, like this:

```
<template>
  <div> <!-- The root -->
    <span></span> <!-- now we can have siblings -->
    <span></span>
  </div>
</template>
```

Try to build a component with a template like this:

```
<template>
  <span></span> <!-- two siblings at the top level of the hierarchy! -->
  <span></span>
</template>
```

and you will get the dreaded error: `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.`

In the vast majority of situations this constraint causes no problems. Have 2 elements that have to go together? Simple add another layer in the DOM hierarchy and wrap them in a div. No problem.

However, there are certain situations in which you _cannot_ simply add an additional layer of hierarchy, situations where the structure of the DOM is super important. For example - I recently had a project where I had two `<td>` elements that always had to go right next to each other. Include one and you had to include the other. Logically, they were a single component, but I couldn't just wrap them in a wrapper because `<td>` elements need to be direct descendants of a `<tr>` to work properly.

## The Solution: Functional Components

The solution to this problem lies in an implementation detail of Vue.js. The key reason why Vue cannot currently support multi-root components lies in the template rendering mechanism - Templates for a component are parsed into an abstract syntax tree (AST), and an AST needs a root!

If you sidestep template rendering, you can sidestep the single-root limitation.

Its less commonly used, but it is entirely possible to implement a Vue.js componenent without a template at all, simply by defining a `render` function. These components, known as functional components, can be used for a myriad of purposes, including _rendering multiple roots in a single component_.

## The Code

For simplicity, I wrote each of my paired `<td>` elements as its own single-file component, and then simply wrapped them in a functional component that passed along props to both of them.

```
/* paired-cell.js */
import FirstCell from '~/components/paired-cell/first-cell';
import SecondCell from '~/components/paired-cell/second-cell';

export default {
  functional: true,
  props: ['person', 'place', 'thing'],
  render(createElement, context) {
    const first = createElement(FirstCell, { props: context.props });
    const second = createElement(SecondCell, { props: context.props });

    return [first, second];
  },
};
```

`FirstCell` and `SecondCell` are standard Vue single file components, each with a `<td>` element as the root. But PairedCell is different - it is a pure JavaScript file that exports a functional component.

There are two key differences between functional components and traditional components.

1. Functional components are _stateless_ (They contain no `data` of their own, and thus their outputs are solely defined by props passed in.
2. Functional components are _instanceless_, meaning there is no `this` context, instead props and related values are passed in via a `context` object.

Looking at what the code is doing then, it states that the component is functional, declares a set of accepted props (a person, place, and a thing), and defines a `render` function that takes two arguments: `createElement` and `context`.

Those two arguments will be provided by Vue. `createElement` is a function that sets up an element in Vue's virtual DOM. You can [directly pass it element properties](https://vuejs.org/v2/guide/render-function.html#createElement-Arguments), but in this case I'm simply using it to render the subcomponents.

The second argument contains the context for the component; in this example the only thing we care about is the `props` which we're passing along, but it also contains things like children, slots, parent, and more - all the things you might need to implement a component.

So to break down what we're doing - we implement a component that accepts a set of props, renders out two child components as siblings, and returns them as an array. Woot! A multi-root component!

* * *

P.S. —  If you’re interested in these types of topics, I send out a weekly newsletter called the ‘[Friday Frontend](https://zendev.com/friday-frontend.html)’. Every Friday I send out 15 links to the best articles, tutorials, and announcements in CSS/SCSS, JavaScript, and assorted other awesome Front-end News. Sign up here: [https://zendev.com/friday-frontend.html](https://zendev.com/friday-frontend.html)