Wrap a Component Inside Another in React
Similarly to how you can wrap one HTML element in another, you can also do that with React components. It’s possible because of composition.
In React, composition is the ability to pass components to other components as props. You can create generic container components that wrap other components like cards, modals and sidebars.
To wrap a component in another component in React you have to use the built-in children
prop.
Here’s an example of a generic card component that can contain any content.
export default function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
Since you don’t know ahead of time what the content is going to be, you need to pass the Card
component a children
prop.
The children
prop contains everything you put between the opening and closing tags of a component. Just like in HTML.
import Card from 'src/components/Card';
export function UserForm() {
return (
<Card>
<h2>Edit Info</h2>
<form>
{/* ✂️ */}
</form>
</Card>
);
}
export function UserInfo() {
return (
<Card>
<h2>User Info</h2>
<p>
{/* Name: ✂️ */}
</p>
</Card>
);
}
Here is some explanation of what’s happening:
- Two components
UserForm
andUserInfo
, reuseCard
component to share one look - Each component passes its own content to the
Card
component - The
Card
component can access that content through itschildren
prop
This results in both components — UserForm
and UserInfo
— rendering Card
component wrapped around their content.
Using Composition in React
One of the most common uses for composition in React is layouts.
When your application has many pages sharing a common look and following the same structure, you should create a layout component.
export default function Layout({ children }) {
return (
<>
<header>
<p>Site Name</p>
</header>
<main>{children}</main>
<footer>
<p>© 2022 Site Name</p>
</footer>
</>
);
}
Now, if you have multiple page components that you can navigate between, they all can reuse this Layout
component.
export function HomePage() {
return (
<Layout>
<h1>Home</h1>
</Layout>
);
}
export function UserPage() {
return (
<Layout>
<h1>User</h1>
</Layout>
);
}
Passing Components as Props
In a page layout, the header and footer usually remain the same while only the main content changes.
But, what if you wanted do something like this:
<header>
{header}
</header>
<main>{children}</main>
<footer>
{footer}
</footer>
This pattern of having multiple adjustable parts of a wrapper component is called slots in other frameworks. It’s not exactly the same in React, but we can achieve similar functionality.
To achieve the functionality of “slots” in React, you can pass as many components through props as you want. You don’t have to rely on just the children
prop.
For example, you can change the header
, footer
, both or none of the following Card
component.
export default function Card({ children, header, footer }) {
return (
<>
{header && <header>{header}</header>}
<section>{children}</section>
{footer && <footer>{footer}</footer>}
</>
);
}
You can pass anything that React can render through header
and footer
. It doesn’t have to be just simple data types.
<Card>
<p>Just content</p>
</Card>
<Card header="Heading text">
<p>Content with a heading</p>
</Card>
<Card header={<h2>Heading</h2>} footer="Footer text">
<p>Content with a heading and a footer</p>
</Card>
<Card footer={<Footer />}>
<p>Content with a footer</p>
</Card>
As you can see, header
and footer
props can contain JSX, plain text and even components. Anything you put between opening and closing tags of Card
goes into children
prop. That’s how you can have many outputs in one wrapper component.
Thanks to the versatility of Card
component and composition, you can create many different Card
variations.