skip to content

In React, what is a Fragment, and what problem does returning `<>...</>` from a component solve that a wrapping `<div>` does not?

level: juniorimportance: must knowfreq 70%

answer

  1. JSX must resolve to one node
  2. the wrapper is a real DOM node
  3. flex and grid items are direct children
  4. groups everything, renders nothing
  5. shorthand cannot carry attributes

basics

~20 s

A Fragment groups several children under one JSX parent while emitting no DOM node. A component can return multiple elements without an extra div that would distort CSS layout, break sibling and child selectors, invalidate HTML nesting, and add noise to the accessibility tree.

solid answer

~50 s

A Fragment is React's way to group children without producing a DOM node. A JSX expression must resolve to a single node, so historically people wrapped groups in a `<div>` — and that div is real: it becomes the flex or grid item instead of your content, it is invalid inside `<tr>` or `<ul>`, it breaks direct-child CSS selectors, and it adds a meaningless node to the accessibility tree. Writing `<>...</>` gives React the single root it needs while rendering nothing at all, so the children land directly inside the parent element. There are two spellings: the shorthand `<>...</>`, and `<React.Fragment>`, which is what you need when the fragment is produced inside a `.map()` and has to carry a `key`. Reach for a real element only when the group genuinely deserves a box — its own background, spacing, a ref, or an ARIA role.

code

jsx · 16 lines
jsx
function ProfileFields({ user }) {
  return (
    <>
      <dt>Name</dt>
      <dd>{user.name}</dd>
    </>
  );
}

function Profile({ user }) {
  return (
    <dl>
      <ProfileFields user={user} />
    </dl>
  );
}

go deeper

for a junior

Know that JSX must resolve to a single node and that <>...</> satisfies that without adding an element to the page. Be able to name one concrete problem an extra wrapper div causes, such as breaking a grid layout.

for a middle

Explain the mechanism rather than the rule: the wrapper is a real element, so it becomes the flex or grid item, changes direct-child selectors, and can be invalid inside table and list parents. Know that the shorthand accepts no attributes at all.

for a senior

Show judgment about when a real element is still correct — the group needs a box, a ref, or an ARIA role — and be ready to explain the failure a stray div causes inside table or list markup, where the HTML parser repairs invalid nesting by relocating the node.

for a principal

Frame it as a component-contract question: whether a shared component is allowed to impose DOM structure on every consumer. Components that emit unnecessary containers make layout non-composable, and that cost compounds across a design system far more than the node count does.

## The single-root rule JSX is not HTML; it is syntax that compiles into JavaScript expressions, and each element you write becomes one value. A `return` statement can only hand back one value, so a component body cannot literally return two adjacent elements. That constraint is where the whole topic starts: you have two `<td>` cells, or a `<dt>`/`<dd>` pair, or a label and its input, and React needs them presented as one thing. The historical workaround was to wrap the group in a container element, usually a `<div>`. It satisfies the compiler, and it is the reflex most people learn first. ## Why the wrapper is not free The wrapper is not a compile-time convenience; it is a real element in the rendered document, and four separate things notice it. **Layout.** In CSS, flex and grid items are the *direct children* of the flex or grid container. If a component returns three inputs inside a wrapper div and you drop that component into a grid, the grid sees one child — the wrapper — and lays out one item. Your three inputs are now stacked inside a single cell. The same applies to `gap`, to `flex-basis`, and to anything else the container distributes over its items. **HTML validity.** Some parents accept only specific children. A `<div>` is not valid between `<tr>` and `<td>`, or between `<ul>` and `<li>`, or between `<dl>` and `<dt>`. When such markup arrives as HTML text the browser's parser repairs it, typically by moving the stray node somewhere else in the document — so what renders is not what you wrote. **CSS selectors.** `.form > input`, `li + li`, and `:nth-child()` all count the actual tree. Insert a level and every direct-child and adjacent-sibling rule aimed at that content stops matching. **Accessibility.** A `<div>` carries no semantics, but it does occupy a position in the tree, and it can sever an implicit relationship — a list whose `<li>` elements are no longer children of the `<ul>` is no longer reliably a list to assistive technology. ## What a Fragment actually does A Fragment is a built-in React component that groups children and renders none of itself. It exists only in the React element tree, never in the DOM. So this: ```jsx function Row({ user }) { return ( <> <td>{user.name}</td> <td>{user.email}</td> </> ); } ``` placed inside a `<tr>` produces exactly two `<td>` elements inside that row. The parent's layout, selectors, and semantics behave as if you had typed the cells there yourself. ## The two spellings `<>...</>` is the shorthand. It is concise and it is what you should reach for by default — but it accepts no attributes whatsoever. `<React.Fragment>...</React.Fragment>` (or `<Fragment>` after `import { Fragment } from 'react'`) is the long form; it is the same component and the only form that can carry a `key`, which matters when the fragment is one entry of a mapped list. A Fragment takes only `key` and `children`. There is no `className`, no `style`, no `ref` — there is no DOM node for any of those to attach to. If you need one, you need a real element. ## Returning arrays A component may also return an array of elements, which is the same idea without the sugar. React then treats the entries as a list, so each one needs a `key`. A fragment reads better for a fixed group; the array form shows up mainly when the children are already produced programmatically. ## When a wrapper is still correct Fragments are not a rule that divs are bad. Keep a real element when the group is a *thing*: it needs a background, a border, padding, a ref for measurement, a click target, or a landmark or ARIA role. The test is whether the box is meaningful. If the only reason the element exists is "JSX made me", it should be a fragment. ## Performance Removing nodes removes work — fewer elements to create, style, and lay out, and slightly less memory. But that is a marginal effect, not a diffing optimisation, and it is the wrong reason to sell fragments. The real argument is that a fragment expresses what you meant: these elements belong to their parent, not to a container you invented.

  • Can a component return an array of elements instead of a fragment, and what changes if it does?
    Yes. Returning an array is legal and renders the entries as siblings, but React treats them as a list, so every entry needs a `key` or you get the missing-key warning. A fragment expresses a fixed group more clearly; the array form is natural only when the children were already built programmatically.
  • Can you attach a className, a ref, or an event handler to a fragment?
    No. A fragment produces no DOM node, so there is nothing for any of those to bind to — `React.Fragment` accepts only `key` and `children`. If you need a style hook, a measurement target, or an event target, render a real element and accept the node deliberately.
  • Do fragments meaningfully improve performance compared with wrapper divs?
    Only marginally. Fewer DOM nodes means slightly less to create, style, and lay out, and a little less memory, which shows up on very large trees. It is not a reconciliation optimisation. Sell fragments on correct layout, valid HTML, and clean semantics rather than on speed.

A Fragment is the paperclip you use to carry several loose sheets to the filing cabinet and then remove before filing them — it holds the group together on the way there and leaves no trace in the finished document.

saying these in an interview costs you the question

  • Says a fragment renders an invisible or zero-height div
  • Claims extra wrapper divs are purely cosmetic and never cause bugs
  • Thinks fragments exist mainly to speed up the virtual DOM
  • States a component can only ever return exactly one element
  • Believes you can put className or a ref on <>...</>

context