Skip to main content

What is fragment in React

React Fragment is a component that groups multiple JSX elements into one return without adding any node to the DOM.

Theory

TL;DR

  • Think plastic wrap around groceries: holds items together for carrying, but disappears once unpacked, nothing in the final HTML
  • <div> adds a real element; Fragment adds zero
  • Short syntax <> and full <Fragment> produce identical output; only <Fragment> accepts key
  • Need one root but a clean DOM: Fragment. Need styling or event handlers on the wrapper: <div>

Quick example

tsx
// div wrapper breaks table layout function BadRow() { return ( <div> <td>Name</td> <td>Email</td> </div> ); } // DOM: <div><td>Name</td><td>Email</td></div> (invalid HTML) // Fragment keeps DOM clean function GoodRow() { return ( <> <td>Name</td> <td>Email</td> </> ); } // DOM: <td>Name</td><td>Email</td>

React requires every component to return exactly one root element. Fragment satisfies that rule without showing up in the browser HTML.

Key difference

<div> solves the "one root" problem but adds a real node to the DOM. That node has layout consequences: it breaks <td> children inside a <tr>, interrupts flex or grid containers, and adds unwanted nesting to semantic HTML. Fragment solves the same problem with zero DOM cost.

When to use

  • Multiple sibling elements from one component: Fragment
  • Table rows or list items where extra wrappers break layout: Fragment
  • Mapping over a list and grouping two siblings per item: <Fragment key={item.id}>
  • Wrapper needs className, style, or a click handler: <div> or a semantic element

Comparison table

Characteristic<div><Fragment> / <>
DOM nodes added10
Supports key propYesYes (full syntax only)
Accepts className, styleYesNo
Affects layoutYesNo
When to useNeeds styling or eventsClean grouping only

How it works

Babel converts both <> and <Fragment> to React.createElement(React.Fragment, null, ...children). During reconciliation React skips DOM node creation for Fragment and mounts children directly under the parent. That is why both syntaxes produce identical HTML output.

Common mistakes

Missing key on Fragment in lists:

tsx
// Wrong: no key, React warns about unstable keys items.map(item => ( <> <li>{item.name}</li> <li>{item.price}</li> </> )); // Correct: key goes on Fragment, not the children items.map(item => ( <Fragment key={item.id}> <li>{item.name}</li> <li>{item.price}</li> </Fragment> ));

<> cannot accept props. Switch to <Fragment> whenever you need a key.

Expecting props to work on Fragment:

tsx
// Ignored: Fragment does not render, style has no effect <Fragment style={{ color: 'red' }}> <p>Not styled</p> </Fragment>

Every prop except key is silently ignored. Use <div> if the wrapper needs styling.

Unnecessary nesting:

tsx
// Redundant: outer Fragment wraps a single child return ( <> <Fragment> <h1>Title</h1> </Fragment> </> ); // Just return <h1>Title</h1> directly

Real-world usage

  • React Table v8: grouping <td> cells inside <tr> without extra nodes
  • Next.js page components: clean JSX to avoid hydration mismatches from unexpected wrapper divs
  • Material-UI: composite components that render sibling elements inside a parent container
  • Conditional rendering of siblings without accumulating nested <div> wrappers

Follow-up questions

Q: What is the difference between <Fragment> and <>?
A: Output is identical. <> is shorthand. The only reason to write <Fragment> is when you need to attach a key prop.

Q: Can Fragment accept a key prop?
A: Yes, but only in full syntax: <Fragment key="...">. Adding attributes to <> is a syntax error.

Q: Why not replace every <div> with Fragment?
A: Fragment cannot carry className, style, or event listeners. When the wrapper itself has to do something, it must be a real element.

Q: Does Fragment appear in React DevTools?
A: Yes, it shows as a "Fragment" node in the component tree. Children remain fully inspectable and debuggable.

Q: How does React handle Fragment in the fiber tree?
A: Fragment is a composite fiber with no host component, so the renderer skips createInstance and mounts children directly onto the parent DOM node. The key prop feeds into the diffing algorithm the same way it does on any other element.

Examples

Grouping table cells

The table case is where a stray <div> causes the most confusion in code reviews - layout breaks and it takes a while to spot the invalid HTML.

tsx
function UserRow({ user }) { return ( <tr> <Fragment key={user.id}> <td>{user.name}</td> <td>{user.email}</td> <td> <button>Edit</button> <button>Delete</button> </td> </Fragment> </tr> ); } // Result: <tr><td>name</td><td>email</td><td>...</td></tr> // No extra nodes, valid HTML

key on Fragment ensures stable reconciliation when UserRow is used inside .map().

Conditional sibling rendering

tsx
function UserProfile({ user, isAdmin }) { return ( <> <h2>{user.name}</h2> <p>{user.email}</p> {isAdmin && ( <> <p>Role: Admin</p> <button>Manage Users</button> </> )} </> ); }

Both levels use <>. The DOM only contains elements that actually render, no wrapper accumulation.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?