react-que-son-y-como-usar-props-children

What are and how to use Children in React

  • 3 min

In the previous chapter, we saw how to pass information from parents to children via Props. We passed a text, a number, or a boolean to configure the component.

But, what if we want to pass another component or HTML code inside another? For example, imagine you want to create a <Card> component, which wraps some content.

Now we don’t just want to configure the title, or this variable or that one. We want to put an HTML fragment inside: a form, a text, an image, a div with three buttons… anything.

For this, React uses a Composition model, which relies on a special prop called children.

When to use Children?

Whenever you find yourself passing props to “draw things” (e.g., textButton="Send", iconButton="save.svg"), ask yourself if it wouldn’t be cleaner to use children (<Button>Send <Icon /></Button>).

The children prop

React has a special rule: Everything you write between the opening and closing tags of a component is automatically passed in the children prop.

Let’s look at this example:

// Component usage
<Button>
  <span>Save</span>
  <IconDiskette />
</Button>
Copied!

Internally, React takes that <span> and that <IconDiskette />, packages them up, and delivers them to the Button component inside props.children.

Implementing the container

For the component to “render” what we passed to it, we have to explicitly render that children prop in the place where we want the content to appear.

It’s like leaving an empty slot reserved.

// Component definition
function Button(props) {
  return (
    <button className="my-button-class">
      {/* Here we dump the content passed to us */}
      {props.children}
    </button>
  );
}
Copied!

If you forget to put {props.children} in the child’s JSX, the content will be ignored and nothing will be displayed.

The “Generic Boxes” Pattern

The most powerful use of this is to create structural components that don’t know what content they will have, they only know what the container looks like.

The classic example is a Card we mentioned earlier:

// Components/Card.jsx
export default function Card({ children, title }) {
  return (
    <div className="card-border-shadow">
      <div className="card-header">
        <h2>{title}</h2>
      </div>
      
      <div className="card-body">
        {/* The "hole" where the variable content will go */}
        {children}
      </div>
    </div>
  );
}
Copied!

Now we can reuse this card for completely different things:

// Usage 1: User Profile
<Card title="User">
  <img src="avatar.jpg" />
  <p>Name: Luis</p>
</Card>

// Usage 2: Error message
<Card title="Critical Error">
  <p>An error has occurred in the system.</p>
  <button>Retry</button>
</Card>
Copied!

The Card doesn’t know what’s inside. It doesn’t care. It only takes care of the border, the shadow, and the title. That’s Composition.

Multiple Slots

Sometimes, a single slot (children) is not enough. Imagine a <Layout> component that needs:

  1. A sidebar.
  2. A main content area.
  3. A footer.

In other frameworks this is called “Named Slots”. In React, we simply remember that props can be anything, including JSX.

We can pass entire components as if they were normal props.

// Components/Layout.jsx
function Layout({ sidebar, content, footer }) {
  return (
    <div className="layout-grid">
      <aside className="sidebar-area">{sidebar}</aside>
      
      <main className="main-area">{content}</main>
      
      <footer className="footer-area">{footer}</footer>
    </div>
  );
}

// Usage
function App() {
  return (
    <Layout
      sidebar={<NavigationMenu />}
      content={<ProductList />}
      footer={<p>© 2024 My Company</p>}
    />
  );
}
Copied!

This pattern avoids having to pass hundreds of configuration props (sidebarColor, sidebarTitle, footerText…). Instead, you simply pass the already assembled component and the Layout only decides where to place it.