Skip to content

Fragments

Let's suppose we want to wind up with the following HTML:

<h1>Welcome to my homepage!</h1>
<p>Don't forget to sign the guestbook!</p>

We copy/paste this HTML into our React application, turning it into JSX. We wind up getting an error though:

Code Playground

import React from 'react';

function App() {
return (
<h1>Welcome to my homepage!</h1>
<p>Don't forget to sign the guestbook!</p>
);
}

export default App;

Something went wrong

/App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (6:4) 4 | return ( 5 | <h1>Welcome to my homepage!</h1> > 6 | <p>Don't forget to sign the guestbook!</p> | ^ 7 | ); 8 | } 9 |

Lint Warning

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

    Rule:

    Location: Line 6, Column 5

  1. /App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (6:4) 4 | return ( 5 | <h1>Welcome to my homepage!</h1> > 6 | <p>Don't forget to sign the guestbook!</p> | ^ 7 | ); 8 | } 9 |
  2. Error in sandbox:
  3. SyntaxError: /App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (6:4) 4 | return ( 5 | <h1>Welcome to my homepage!</h1> > 6 | <p>Don't forget to sign the guestbook!</p> | ^ 7 | ); 8 | } 9 | at https://sandpack-bundler.vercel.app/static/js/sandbox.0997091ea.js:1:257525 at e.value (https://sandpack-bundler.vercel.app/static/js/sandbox.0997091ea.js:1:257644) at e.value (https://sandpack-bundler.vercel.app/static/js/sandbox.0997091ea.js:1:255896) at Worker.<anonymous> (https://sandpack-bundler.vercel.app/static/js/sandbox.0997091ea.js:1:256504)

The error message is telling us to use a “JSX fragment”, and we'll learn all about that shortly. But first, let's take a moment and think about it. Why does this produce an error?

Spend a couple minutes tinkering with the problem. Can you figure out why this is invalid?

After poking at the problem for a couple of minutes, watch this video for an explanation:

Video Summary

This is one of those situations where the JSX obscures what the real issue is. If we convert it into pure JS, the issue becomes a bit more clear:

function App() {
return (
React.createElement('h1', {}, 'Welcome to my homepage!')
React.createElement('p', {}, "Don't forget to sign...")
);
}

We have two separate React.createElement function calls, and we're trying to return both of them. This isn't allowed in JavaScript!

To move away from React altogether, it's the equivalent of trying to do this:

function something() {
let arr = [1, 2, 3];
return (
arr.push(4)
arr.push(5)
);
}

Return statements have space for a single expression, but we're packing two expressions in there! For more information, check out the Statements Vs. Expressions 👀 reference lesson.

So, that's why this code is invalid. How can we fix it?

One option is to wrap both React elements in a div:

return (
<div>
<h1>Welcome to my homepage!</h1>
<p>Don't forget to sign the guestbook!</p>
</div>
);

If we examine the raw JS, we see that we're no longer returning multiple expressions:

return (
React.createElement(
'div',
{},
React.createElement('h1', {}, 'Welcome…'),
React.createElement('p', {}, "Don't forget…"),
);
);

So, this fixes the syntax error, but it's not really ideal. It pollutes the DOM with unnecessary elements. And it can even lead to accessibility and layout issues, like this:

Code Playground

import React from 'react';

function App() {
return (
<ul>
<ListItems />
<li>Item 3</li>
<li>Item 4</li>
</ul>
);
}

function ListItems() {
return (
<div>
<li>Item 1</li>
<li>Item 2</li>
</div>
);
}

export default App;

In this example, the list items are meant to be displayed in a single row, but the <div> breaks the Flexbox algorithm. It also produces invalid markup, which means that it might cause problems for folks who rely on assistive technologies like screen readers.

Fortunately, there's a better way. We can use fragments.

A fragment is a special React component that does not produce a DOM node. It looks like this:

Code Playground

import React from 'react';

function App() {
return (
<React.Fragment>
<h1>Welcome to my homepage!</h1>
<p>Don't forget to sign the guestbook!</p>
</React.Fragment>
);
}

export default App;

If we inspect the output in our developer tools, we see that our two HTML elements, <h1> and <p>, sit directly inside the container element (<div id="root">):

Screenshot of the DOM structure from the above code playground

Fragments allow us to respect the rules of JavaScript without polluting the HTML. They're a great option!

Shorthand

React fragments can also be created using the following syntax:

return (
<>
<h1>Welcome to my homepage!</h1>
<p>Don't forget to sign the guestbook!</p>
</>
);

This shorthand syntax might seem a bit more magical / strange, but I kinda like it. It shows that it's an "empty" HTML tag.

Either way, the JSX will compile to the exact same JavaScript:

React.createElement(
React.Fragment,
{},
/* Children here */
);

The React team included this special component specifically to allow us to return multiple elements from a component without polluting the DOM. It's a great tool!