HOME

This is why you can't return adjacent JSX elements.

I've been using React for quite some time now and it's an amazing tool to write maintainable applications pretty fast. But I remember when I started learning it, I was shown my first error by the instructor

Syntax error: Adjacent JSX elements must be wrapped in an enclosing tag

And he straightaway told that you can only return a single element from a component, if you have more than one just wrap them all in a parent element like a

div

or

React.Fragment

(which I came to know about later).

And I was like pixel thumbs up unicorn

Okay! I can remember that.

But to anyone who is starting with React, you don't have to do that.

P.S.

Picture of a Unicorn being happy and agreeing(i.e. thumbs up). I wanted to tell this explicitly as the image can be a little pixelated. Pun Intended.

Understanding how React works

Let us see what is happening under the hood when you are writing JSX and easing through the development process.

JSX is just a syntactic sugar over the createElement method of the React library, but a sugar so sweet no one can avoid it(and no one should). What this means is what you can do with JSX can be done with React.createElement()

Let's start by making a

h1

element.

React.createElement("h1", { id: "myHeading" }, "Unicorn Party Here");

Let me break

createElement

to you, the first argument it takes defines the type of element we want to create. The second argument takes an object of element's properties and here we are giving it an id. The third argument are its children i.e. anything you would have put between the opening and closing tags like <h1>👉 children here</h1> in normal HTML.

This will make an actual

h1

while rendering that looks like <h1 id="myHeading">Unicorn Party Here</h1>

How to add children elements to a parent element

Instinctively thinking from what we saw above, children elements can be added as follows

React.createElement(
  "ul",
  null,
  React.createElement("li", null, "Item one"),
  React.createElement("li", null, "Item two"),
  React.createElement("li", null, "Item three")
);

This will be rendered as

<ul>
  <li>Item one</li>
  <li>Item two</li>
  <li>Item three</li>
</ul>

We can see that any number of arguments after the second argument are taken as children arguments. This is what happens when you write JSX, it uses createElement and renders the DOM as shown in the examples.

The return statement

Now let's rethink what can we return from a function in JavaScript. With the obvious numbers, strings out of the way functions can return anything in between arrays, objects and even other function but lets look at some caveats with the return statement.

function square(a) {
  return
  a * a;
}

this will be converted to

function square(a) {
  return;
  a * a;
}

as the return statement is affected by automatic semicolon insertion, so no line breaks are allowed. Read more at MDN.

So we use parenthesis() to prevent return from adding automatic semicolon.

function square(a) {
  return (
    a * a;
  )
}

This will return the correct answer.

But looking at the next line you'll say, What Unicorn milk am I drinking 🤷‍♀️🤷‍♂️?

function returnSelf(a, b) {
  return (
    a
    b
  )
}

This is simply

wrong syntax

So when you try to return two adjacent JSX elements

return (
  <h1>Hello World</h1>
  <p>Are Unicorns even real?</p>
);

which is the same as

return (
  React.createElement("h1", null, "Hello World")
  React.createElement("p", null, "Are Unicorns even real?")
);

is also the same

wrong syntax

.

But wrapping it all in a div sounds like a perfect solution and it is

return (
  <div>
    <h1>Hello World</h1>
    <p>Are Unicorns even real?</p>
  </div>
);

which is the same as

return (
  React.createElement("div", {id: "container"},
    React.createElement("h1", null, "Hello World"),
    React.createElement("p", null, "Are Unicorns even real?")
  )
);

And this is perfectly valid syntax, I mean we are returning single values from the time we started coding. In fact anything that is valid would work, you can also try returning an array of elements like this.

import React from 'react';
import ReactDOM from 'react-dom';

function ReturnJSXArray() {
  return [<h1>The End</h1>, <h3>🦄🦄🦄🦄</h3>];
}

ReactDOM.render(<ReturnJSXArray />, document.getElementById('root'));

And React will actually render these.

Once you've read this, it seems very obvious that a wrapper is needed for adjacent JSX or you can even return arrays of JSX(which you should avoid) but being so hooked up in learning React we tend to forget the obvious.