Marius Schulz
Marius Schulz
Front End Engineer

JSX Fragment Syntax in TypeScript

TypeScript 2.6 added support for JSX fragments. Within .tsx files, you can now use the new <>...</> syntax to create a fragment.

#Motivation Behind JSX Fragments

In React, it's a common pattern to return multiple elements from a component. For instance, let's say we want to render multiple list items within the following component:

class List extends React.Component {
  render() {
    return (
      <ul>
        <ListItems />
        <li>Item 3</li>
      </ul>
    );
  }
}

However, in our ListItems component, we cannot simply return multiple adjacent JSX elements like this:

class ListItems extends React.Component {
  render() {
    return (
      <li>Item 1</li>
      <li>Item 2</li>
    );
  }
}

Adjacent JSX elements must be wrapped in an enclosing element, so we could add a wrapping div element:

class ListItems extends React.Component {
  render() {
    return (
      <div>
        <li>Item 1</li>
        <li>Item 2</li>
      </div>
    );
  }
}

Unfortunately, adding such a wrapper breaks the structure of our list. Our ListItems component currently renders the following DOM elements:

<ul>
  <div>
    <li>Item 1</li>
    <li>Item 2</li>
  </div>
  <li>Item 3</li>
</ul>

Note that the <div> doesn't belong in there. We can get rid of it by using the JSX fragment syntax instead:

class ListItems extends React.Component {
  render() {
    return (
      <>
        <li>Item 1</li>
        <li>Item 2</li>
      </>
    );
  }
}

A fragment lets us group multiple JSX elements without adding an extra wrapper node. Now, our List component renders the expected markup:

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

Alternatively, we could've explicitly written React.Fragment instead of using the new JSX syntax:

class ListItems extends React.Component {
  render() {
    return (
      <React.Fragment>
        <li>Item 1</li>
        <li>Item 2</li>
      </React.Fragment>
    );
  }
}

The two versions of our ListItems component are equivalent and render exactly the same output (given that we compile our JSX for use with React).

#Compiling JSX Fragments with TypeScript

Here's our ListItems component with the new JSX syntax again:

class ListItems extends React.Component {
  render() {
    return (
      <>
        <li>Item 1</li>
        <li>Item 2</li>
      </>
    );
  }
}

If we compile the .tsx file with --jsx react (and --target es2015), the following JavaScript is emitted:

class ListItems extends React.Component {
  render() {
    return (
      React.createElement(
        React.Fragment,
        null,
        React.createElement("li", null, "Item 1"),
        React.createElement("li", null, "Item 2")
      )
    );
  }
}

The compiler replaces the short fragment syntax by a call to the React.createElement() method and passes it React.Fragment as the first argument.

If we compiled our ListItems component with --jsx preserve (and --target es2015) instead, our JSX would be emitted unchanged, set aside whitespace:

class ListItems extends React.Component {
  render() {
    return (
      <>
        <li>Item 1</li>
        <li>Item 2</li>
      </>
    );
  }
}

This post is part of the TypeScript Evolution series.