Understanding React.Fragment: What It Is and Why We Need It
React developers are used to wrapping multiple JSX elements using <Fragment>, <React.Fragment>, or the shorthand syntax <>...</>. But why is Fragment needed in the first place?
Why Do We Need Fragments?
If you try to return multiple sibling elements from a component without wrapping them, like this:
return (
<span>First element</span>
<span>Second element</span>
)
You’ll get a syntax error like:
JSX expressions must have one parent element.
or
Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?
This is because JSX must return a single parent element. Under the hood, JSX is just syntactic sugar that gets transformed into plain JavaScript objects using React.createElement.
So the example above would compile to something like this:
{
type: 'span',
props: {
children: "First element"
}
}
{
type: 'span',
props: {
children: "Second element"
}
}
React expects to receive a single React element, not two separate ones. And when rendering a component, React internally iterates over the children, expecting a structure that is iterable — like an array or a single object with nested children.
That’s why we need a wrapper like Fragment.
What Does React Do with a Fragment?
When using React.Fragment, the compiled output looks more like this:
{
type: React.Fragment,
props: {
children: [
{
type: 'span',
props: { children: 'First element' }
},
{
type: 'span',
props: { children: 'Second element' }
}
]
}
}
Fragment allows us to group multiple elements without adding an extra DOM node — like a div or a span.
But… What Is Fragment?
React.Fragment is a special kind of component — it’s a React exotic component that accepts children (and optionally a key).
Here’s the type definition:
(alias) const Fragment: ExoticComponent<{ children?: ReactNode }>
An ExoticComponent is a type of component that React treats in a special way:
interface ExoticComponent<P = {}> {
(props: P): ReactNode;
readonly $$typeof: symbol;
}
Notice the $$typeof property — this is an internal marker React uses to identify React elements. It’s essentially what tells React, “Hey, I’m a valid React element,” especially useful when multiple versions of React are present or in debugging scenarios.
The Anatomy of a React Element
When you create a React element, say:
const element = React.createElement("span", null, "Hello World");
You get an object like this:
{
$$typeof: Symbol(react.element),
type: "span",
key: null,
ref: null,
props: {
children: "Hello World"
}
}
Here:
typedetermines what kind of node it is (e.g.,"div","span", or a custom component).$$typeofhelps React recognize this as an element it should process.
For a Fragment, you can do something like:
const fragment = React.createElement(React.Fragment, null, [element, element]);
And the output will look like:
{
$$typeof: Symbol(react.element),
type: Symbol(react.fragment),
key: null,
ref: null,
props: {
children: [
{
$$typeof: Symbol(react.element),
type: "span",
props: { children: "Hello World" },
key: null,
ref: null,
},
{
$$typeof: Symbol(react.element),
type: "span",
props: { children: "Hello World" },
key: null,
ref: null,
}
]
}
}
So even though Fragment is not rendered in the DOM, React still treats it as a full-fledged React element with the $$typeof: Symbol(react.element), and its own type: Symbol(react.fragment).
Fragments are a simple but powerful feature in React. They solve the fundamental limitation of JSX requiring a single parent element, without bloating your DOM with unnecessary wrapper nodes.
Use them when:
- You need to return multiple elements from a component.
- You want to avoid unnecessary
<div>wrappers (hello, clean DOM). - You care about minimal DOM structure for styling, accessibility, or performance.
Next time you see <>...</>, remember - there’s some elegant React machinery under the hood making that possible.