Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Children and composition

Sometimes a component needs not a value but a whole piece of markup: a card with a border that can contain anything. Such a piece is passed between the opening and closing tag, and the component receives it in a special prop, children. Building an interface from components nested inside each other like this is called composition.

A wrapper component

Create src/components/Card.jsx:

// src/components/Card.jsx
export default function Card({ children }) {
  return <div className="card">{children}</div>;
}

children is whatever ends up between the Card tags. The component renders it inside the border and knows nothing about the content.

Using it

// src/App.jsx
import Card from './components/Card.jsx';
 
export default function App() {
  return (
    <Card>
      <h2>Buy milk</h2>
      <p>By the evening, at the shop nearby.</p>
    </Card>
  );
}

The page shows a block with the class card containing a heading and a paragraph. Add the rule .card { border: 1px solid #ccc; padding: 16px; } to src/index.css to see the border.

A wrapper with props

children combines with ordinary props. For example, a panel with a title — src/components/Panel.jsx:

// src/components/Panel.jsx
export default function Panel({ title, children }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {children}
    </section>
  );
}
// src/App.jsx
import Panel from './components/Panel.jsx';
import TodoItem from './components/TodoItem.jsx';
 
export default function App() {
  return (
    <Panel title="Today">
      <ul>
        <TodoItem todo={{ id: 1, text: 'Buy milk', done: false }} />
        <TodoItem todo={{ id: 2, text: 'Call Oleg', done: true }} />
      </ul>
    </Panel>
  );
}

The "Today" panel shows a list of two tasks. The same panel can be used for a "Tomorrow" block with different content.

A page frame

children is handy for a shared frame: the header and footer stay the same, the middle changes. Create src/components/Layout.jsx:

// src/components/Layout.jsx
export default function Layout({ children }) {
  return (
    <>
      <header>My tasks</header>
      <main>{children}</main>
      <footer>2026</footer>
    </>
  );
}

In App, all page content is wrapped in Layout. Later, in the routing chapter, a shared page layout plays a similar role.

What to use when

You need to passWay
A value: text, number, objectAn ordinary prop
A piece of markup inside the componentchildren
Several pieces of markup in different placesSeveral props holding JSX, e.g. header and footer

Common mistake

A wrapper component must render children itself. If you forget, the nested markup disappears without any error:

// Wrong: the content between the Card tags does not appear.
export default function Card() {
  return <div className="card"></div>;
}

Accept children in the parameters and put {children} where it belongs in the markup.

Thanks for reading!

Donate to the site — we work hard for you.