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 article and 44 others are part of the TypeScript Evolution series. Have a look!