Skip to content

Exposing React.Fragment

One of the most common error messages while creating React apps is SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag.

We would get such an error if we try rendering MyComponent.

const MyComponent = () => {
  return (
    <h2>Hello...</h2>
    <p>World!</p>
  );
};

This happens because, under the hood, JSX elements are converted to HTML elements by calling React.createElement.

React.createElement(type, [props], [...children])

For example, the following JSX element:

const elem = <div className="container">Hello world!</div>;

Is converted – by the Babel React plugin – to a Javascript function call:

const elem = React.createElement(
  "div",
  { className: "container" },
  "Hello world!"
);

Additionally, children nodes…

<div>
  <div>Child 1</div>
  <div>Child 2</div>
</div>;

…are passed as optional ...children arguments.

React.createElement(
  "div",
  null,
  React.createElement("div", null, "Child 1"),
  React.createElement("div", null, "Child 2")
);

A single root element

However, see that while React.createElement can accept an undefined amount of children nodes, it takes only a single root element – the type argument. There lies the issue. Our example component:

const MyComponent = () => {
  return (
    <h2>Hello...</h2>
    <p>World!</p>
  );
};

Would try to return two separate expressions, which is not a valid Javascript return statement. Only a single expression can be returned.

const myComponent = () => {
  return (
    React.createElement("h2", null, "Hello...");
    React.createElement("p", null, "World!");
  );
};

Enclosing in a single parent element

A straightforward solution to render MyComponent, would enclose both elements inside a single wrapper.

const MyComponent = () => {
  return (
    <div>
      <h2>Hello...</h2>
      <p>World!</p>
    </div>
  );
};

While this approach is correct, it has the disadvantage of creating an extra wrapper component. This can hurt the semantics of the page, invalidate CSS selectors, and create deeply nested <div> trees for complex components.

React.Fragment

In order to avoid the above issues, we can wrap both elements in a custom React element, React.Fragment.

const MyComponent = () => {
  return (
    <React.Fragment>
      <h2>Hello...</h2>
      <p>World!</p>
    </React.Fragment>
  );
};

This will be transpiled to:

const MyComponent = () => {
  return React.createElement(
    React.Fragment,
    null,
    React.createElement("h2", null, "Hello..."),
    React.createElement("p", null, "World!")
  );
};

Which can then be used to render the native <h2> and <p> elements…

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

…Without any wrapper HTML element.

<div id="root">
  <h2>Hello...</p2>
  <p>World!</p>
</div>

However, what exactly is React.Fragment?

Create a Fragment component

While the way React renders elements to the DOM is very intricate, we can emulate a Fragment component quite easily. I found this approach in Maximilian Schwarzm├╝ller’s React course.

The implementation is very simple. We create a custom component that simply returns its children.

const MyFragment = (props) => props.children;

If we enclose MyComponent children nodes inside the MyFragment component, we’ll get the same result as using React.Fragment.

const MyComponent = () => {
  return (
    <MyFragment>
      <h2>Hello...</h2>
      <p>World!</p>
    </MyFragment>
  );
};

The <h2> and <p> elements will be rendered without any enclosing tag (besides the root container).

<div id="root">
  <h2>Hello...</p2>
  <p>World!</p>
</div>
Published inProgramming
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments