Volume I index
JSX Is Real React Code

Fragments and Nested Trees

Ishtmeet Singh @ishtms/July 14, 2026/6 min read
#react#jsx#fragments#html#components

A component call returns one JavaScript value. A fragment is one React value that can contain several sibling nodes without creating another browser element around them.

jsx
function ChapterHeading() {
  return (
    <>
      <p>Chapter 3</p>
      <h1>JSX Is Real React Code</h1>
    </>
  );
}

The <> and </> tags form the short fragment syntax. React follows both children. React DOM creates the paragraph and heading, but no fragment DOM node.

Fragments solve React grouping. They do not replace useful HTML parents.

Inspect the Host Result

Render ChapterHeading inside a header.

jsx
function App() {
  return (
    <header>
      <ChapterHeading />
    </header>
  );
}

The host tree is equivalent to this structure.

html
<header>
  <p>Chapter 3</p>
  <h1>JSX Is Real React Code</h1>
</header>

There is no element between header and p. The fragment only groups the two child element descriptions in the React result.

This affects CSS selectors based on direct children.

css
header > h1 {
  color: #61dafb;
}

The selector still matches because no wrapper was added.

Use a Real Element for Document Meaning

This content has a clear section relationship.

jsx
function LessonOverview() {
  return (
    <section aria-labelledby="lesson-overview-title">
      <h2 id="lesson-overview-title">Lesson overview</h2>
      <p>Fragments and nested trees</p>
    </section>
  );
}

The section communicates document structure and gives the heading an associated region. Replacing it with a fragment removes that semantic parent.

Use a host element when the parent needs any of these roles.

  • document semantics
  • a CSS class or layout rule
  • an event handler
  • an accessible name or state
  • a DOM ref
  • a host property such as hidden

A fragment cannot receive className or a normal DOM event prop because there is no host node on which to place them.

jsx
<Fragment className="panel">...</Fragment>

React does not turn that fragment into a styled container.

Avoid Wrappers Added Only for JSX Syntax

A component may need two table cells.

jsx
function LessonCells() {
  return (
    <>
      <td>Fragments</td>
      <td>12 min</td>
    </>
  );
}

The row can use the component.

jsx
<tr>
  <LessonCells />
</tr>

The host result places two td elements directly inside tr. A div wrapper would produce invalid table structure.

Lists have a different requirement. Each repeated item should still be a list item.

jsx
<ul>
  <li>Expressions Inside JSX</li>
  <li>Attributes and Styles</li>
</ul>

A fragment must not be used to place bare text and headings directly inside a ul. The HTML list requires li children. Fragments do not suspend host nesting rules.

The Short Syntax Accepts No Props

This is the concise form.

jsx
<>
  <dt>Fragment</dt>
  <dd>A React grouping value</dd>
</>

There is no opening tag name where props can be written. The following form is invalid syntax.

jsx
< key={term.id}>
  <dt>{term.name}</dt>
  <dd>{term.definition}</dd>
</>

Import the named Fragment component when the fragment needs a key.

jsx
import { Fragment } from "react";
jsx
<Fragment key={term.id}>
  <dt>{term.name}</dt>
  <dd>{term.definition}</dd>
</Fragment>

The key identifies the group among sibling list results. The named fragment form accepts that key.

A Fragment Can Be a Component's Root Result

This component returns three host siblings.

jsx
function LessonMetadata() {
  return (
    <>
      <span>Chapter 3</span>
      <span>Lesson 3</span>
      <span>12 min</span>
    </>
  );
}

The component still returns one React value. The parent receives the three host nodes at the component's position.

Whether those spans need a parent depends on the caller.

jsx
<div className="lesson-metadata">
  <LessonMetadata />
</div>

The parent supplies the layout container. LessonMetadata supplies only the items.

This can be appropriate when the component always lives inside a parent that provides the group. If the metadata needs an accessible label or layout role, give the component a real container instead.

Fragments Do Not Isolate CSS

The fragment does not create a styling scope.

jsx
function LessonMetadata() {
  return (
    <>
      <span className="label">Chapter 3</span>
      <span className="label">Lesson 3</span>
    </>
  );
}

Selectors from the surrounding page can match both spans normally. Inherited CSS comes from their actual DOM parent, not from the fragment.

If the component needs a local layout context, use a host element with a class.

jsx
function LessonMetadata() {
  return (
    <div className="lesson-metadata">
      <span>Chapter 3</span>
      <span>Lesson 3</span>
    </div>
  );
}

The div is justified by a layout requirement. It is not present only to satisfy a JSX parser.

Fragments Do Not Stop Event Propagation

Events propagate through the actual host tree. A fragment adds no DOM event target.

jsx
<section onClick={handleSectionClick}>
  <>
    <button type="button">Open</button>
    <button type="button">Save</button>
  </>
</section>

Click events from both buttons can propagate to the section. There is no fragment node where a listener can be attached or propagation can stop.

The fragment rule is structural. No DOM node means no DOM listener location.

Nested Components Can Return Different Root Types

LessonNotice can return a paragraph while LessonList returns a list.

jsx
function LessonArea() {
  return (
    <section>
      <LessonNotice />
      <LessonList />
    </section>
  );
}

React resolves each component into its returned React nodes. The final host tree must still be valid under the section.

text
LessonArea component
  section host element
    LessonNotice component
      p host element
    LessonList component
      ul host element

Component nesting and host nesting remain separate views of the same rendered work.

Do Not Add a Fragment Around One Child

This fragment has no grouping work.

jsx
function LessonTitle() {
  return (
    <>
      <h2>Fragments</h2>
    </>
  );
}

Return the child directly.

jsx
function LessonTitle() {
  return <h2>Fragments</h2>;
}

An unnecessary fragment usually has little runtime cost, but it adds syntax and suggests that multiple siblings or grouping behavior exists when it does not.

Decide with the Host Tree

Before choosing a wrapper, write the required DOM relationship.

text
article
  header
    p
    h2
  p

The header is a useful semantic parent. A fragment should not replace it.

For table cells, the required relationship is different.

text
tr
  td
  td

A fragment-returning component can supply those sibling cells without inserting an invalid node.

Inspect the Elements panel after rendering. The actual host tree should match the intended HTML structure.

Lesson Check

The fragment decision now follows one direct test.

text
React needs one grouping value
browser document needs a parent -> use an HTML element
browser document needs sibling nodes only -> use a fragment

Source Notes