DEV Community

Cover image for This is why you can't return adjacent JSX elements.
Tushar Kashyap
Tushar Kashyap

Posted on • Updated on

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
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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")
);
Enter fullscreen mode Exit fullscreen mode

This will be rendered as

<ul>
  <li>Item one</li>
  <li>Item two</li>
  <li>Item three</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

this will be converted to

function square(a) {
  return;
  a * a;
}
Enter fullscreen mode Exit fullscreen mode

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;
  )
}
Enter fullscreen mode Exit fullscreen mode

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
  )
}
Enter fullscreen mode Exit fullscreen mode

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>
);
Enter fullscreen mode Exit fullscreen mode

which is the same as

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

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>
);
Enter fullscreen mode Exit fullscreen mode

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?")
  )
);
Enter fullscreen mode Exit fullscreen mode

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'));
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (18)

Collapse
 
hisham profile image
Hisham Mubarak

I've had to use the <> </> a few times, and also returned elements inside arrays a few times too, after this adjacent JSX error came up. Finally I understood why is the way is it. Thanks for the nice article.

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap

Glad I could help.

Collapse
 
myogeshchavan97 profile image
Yogesh Chavan

Nice explanation. I have also written a similar article some time back with additional details which you can check out here

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap • Edited

I checked it out, good work.
Check out his article to see more about how React.createElement works.

Collapse
 
myogeshchavan97 profile image
Yogesh Chavan

Thank you so much!

Collapse
 
itsjzt profile image
Saurabh Sharma • Edited

You can always return

function returnSelf(a, b) {
  return [
    a,
    b
  ]
}
Collapse
 
tusharkashyap63 profile image
Tushar Kashyap

Yes I said we can return arrays

Collapse
 
thehanimo profile image
Hani • Edited

What if React could automatically add <>, </> around these adjacent JSX elements?

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap • Edited

But your program will never reach that stage when React can do anything. Wrong syntax will break your program in the first place. Please abide by the rules of JavaScript as React is just JavaScript.

Collapse
 
thehanimo profile image
Hani

I mean, while compiling, can’t React intelligently figure it out and add a parent block? I know it doesn’t do that now but it is quite possible isn’t it?

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
devhammed profile image
Hammed Oyedele

That is asking too much 😅

React is just a library.

Collapse
 
thebuildguy profile image
Tulsi Prasad

Great writeup!

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap

Thank you so much :)

Collapse
 
wannabehexagon profile image
ItsThatHexagonGuy

You get that error because you can only return one thing at any given time. That error translates to "do something so you will only return one thing".

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap • Edited

I know it asks you to return one element. In this article I'm trying to explain WHY does it want you to return one element.

Collapse
 
paras594 profile image
Paras 🧙‍♂️

Great post and explanation !!

Collapse
 
tusharkashyap63 profile image
Tushar Kashyap

Thank you, Paras :)