React Fragments

Difficulty: Beginner

React Fragments let you group a list of children without adding extra nodes to the DOM. In React, a component must return a single element. Before Fragments existed, developers would wrap sibling elements in a `<div>`, adding unnecessary nodes to the DOM tree. Fragments solve this problem by providing an invisible wrapper that groups elements without rendering any additional HTML.

There are two syntaxes for Fragments. The explicit syntax is `<React.Fragment>...</React.Fragment>`, and the short syntax is `<>...</>`. The short syntax is cleaner and more commonly used. However, the explicit `<React.Fragment>` syntax supports a `key` prop, which is necessary when rendering lists of Fragments. The short syntax does not support any props at all.

Fragments are particularly useful in several scenarios. When a component needs to return multiple table rows or list items, wrapping them in a div would create invalid HTML (a div inside a table, for instance). Fragments let you return multiple `<tr>` elements from a component without breaking the table structure. They are also useful when you want to render adjacent elements without adding a wrapper that might interfere with CSS layouts like Flexbox or Grid.

Under the hood, Fragments are lightweight. They do not create a real DOM node, so they have zero impact on performance and do not affect CSS styling or the HTML structure. When React processes a Fragment, it simply renders the children directly. This means your rendered HTML stays clean and semantic, with no extra wrapper divs cluttering the markup.

A common pattern is to use Fragments at the top level of a component return when you have sibling elements. Instead of adding a meaningless div, use `<>` and `</>` to wrap them. This keeps your DOM tree shallow and your HTML valid. Remember that the only time you need the full `<React.Fragment>` syntax is when you need to add a key prop, typically when mapping over an array.

Code examples

Why Fragments Are Needed

// Without fragments: extra div in the DOM
function WithDiv() {
  return {
    type: 'div', // Unnecessary wrapper!
    props: {
      children: [
        { type: 'h1', props: { children: 'Title' } },
        { type: 'p', props: { children: 'Content' } }
      ]
    }
  };
}

// With fragments: no extra DOM node
function WithFragment() {
  // React.Fragment renders no DOM element
  return {
    type: 'Fragment',
    props: {
      children: [
        { type: 'h1', props: { children: 'Title' } },
        { type: 'p', props: { children: 'Content' } }
      ]
    }
  };
}

const withDiv = WithDiv();
const withFrag = WithFragment();
console.log('With div wrapper: ' + withDiv.type);
console.log('With fragment: ' + withFrag.type);
console.log('Children count: ' + withFrag.props.children.length);

Fragments act as invisible wrappers. The children are rendered directly without any extra DOM node, keeping the markup clean.

Fragment Syntax Variants

// Short syntax: <> </>
// Used when you don't need any props
function ShortSyntax() {
  // In real JSX: <><h1>Hello</h1><p>World</p></>
  return [
    { type: 'h1', props: { children: 'Hello' } },
    { type: 'p', props: { children: 'World' } }
  ];
}

// Explicit syntax: <React.Fragment key={id}>
// Used when you need a key (e.g., in lists)
function ExplicitSyntax(items) {
  return items.map(item => ({
    type: 'Fragment',
    key: item.id,
    props: {
      children: [
        { type: 'dt', props: { children: item.term } },
        { type: 'dd', props: { children: item.def } }
      ]
    }
  }));
}

const short = ShortSyntax();
console.log(short.map(el => el.type).join(', '));

const items = [{ id: 1, term: 'JSX', def: 'Syntax extension' }];
const explicit = ExplicitSyntax(items);
console.log('Key: ' + explicit[0].key);

Use the short syntax (<></>) when no props are needed. Use <React.Fragment key={}> when rendering lists that need keys.

Practical Use Case: Table Rows

// A component returning multiple table rows
// Without Fragment this would need a wrapper div (invalid in <table>)
function UserRows(props) {
  return props.users.map(user => ({
    type: 'tr',
    key: user.id,
    props: {
      children: [
        { type: 'td', props: { children: user.name } },
        { type: 'td', props: { children: user.email } }
      ]
    }
  }));
}

const users = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' }
];

const rows = UserRows({ users });
rows.forEach(row => {
  const cells = row.props.children;
  console.log(cells[0].props.children + ' | ' + cells[1].props.children);
});

Fragments are essential when returning multiple table rows, list items, or other elements where a wrapper div would create invalid HTML.

Key points

Concepts covered

React.Fragment, fragment short syntax, avoiding unnecessary DOM nodes, fragment keys, component return types