Master the children prop, learn composition patterns over inheritance, and build flexible, reusable components using containment and specialization patterns.
In HTML, elements can contain other elements: <div><p>Hello</p></div>. React works the same way. When you put JSX between the opening and closing tags of a component, React passes that JSX as a special prop called children.
function Wrapper({ children }) {
return (
<div style={{ border: '2px solid blue', padding: '16px' }}>
{children}
</div>
);
}
// Usage:
<Wrapper>
<h1>Hello!</h1>
<p>This content is passed as children.</p>
</Wrapper>The children prop can be anything: text, JSX elements, components, or even an array of elements. React renders whatever you pass as children.
// Text as children
<Wrapper>Just a string</Wrapper>
// Multiple elements as children
<Wrapper>
<Header />
<Sidebar />
<MainContent />
</Wrapper>
// Nested components as children
<Wrapper>
<Wrapper>
<p>Nested!</p>
</Wrapper>
</Wrapper>The children prop is the foundation of component composition in React. It allows you to create generic container components that do not need to know their contents in advance. The component defines the structure and styling, and the caller decides what goes inside.
You can access children through destructuring ({ children }) or through props.children:
// Both are equivalent:
function Box({ children }) {
return <div className="box">{children}</div>;
}
function Box(props) {
return <div className="box">{props.children}</div>;
}In object-oriented programming, inheritance is a common way to share behavior between classes. But in React, composition is always preferred over inheritance.
The React team at Meta (with thousands of components in production) has stated that they have not found any use cases where they would recommend using inheritance over composition.
Why composition wins:
Flexibility. A component that uses children can wrap any content without modification. An inherited component is locked into its parent's structure.
Explicitness. Props make the data flow visible. Inheritance hides behavior in the class hierarchy.
Simplicity. Composition is just passing props and rendering children. Inheritance requires understanding the entire class chain.
Inheritance approach (not recommended):
// Imagine if components used inheritance:
class SuccessDialog extends Dialog {
render() {
return super.render({ color: 'green', title: 'Success!' });
}
}
// Hard to understand, hard to customizeComposition approach (recommended):
function Dialog({ title, color, children }) {
return (
<div style={{ border: `2px solid ${color}`, padding: '16px' }}>
<h2>{title}</h2>
{children}
</div>
);
}
function SuccessDialog({ children }) {
return (
<Dialog title="Success!" color="green">
{children}
</Dialog>
);
}
// Easy to understand, easy to customize
<SuccessDialog>
<p>Your changes have been saved.</p>
</SuccessDialog>Composition lets you build complex UIs from simple, reusable pieces — like LEGO blocks. Each component handles its own responsibility, and they snap together through props and children.
A common composition pattern is creating specialized versions of a generic component. The specialized component wraps the generic one and provides specific default props.
// Generic component
function Button({ variant, size, children, onClick }) {
const styles = {
padding: size === 'large' ? '12px 24px' : '8px 16px',
backgroundColor: variant === 'danger' ? 'red' : 'blue',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
};
return (
<button style={styles} onClick={onClick}>
{children}
</button>
);
}
// Specialized components
function DangerButton({ children, onClick }) {
return (
<Button variant="danger" size="large" onClick={onClick}>
{children}
</Button>
);
}
function PrimaryButton({ children, onClick }) {
return (
<Button variant="primary" size="large" onClick={onClick}>
{children}
</Button>
);
}This pattern is useful for:
// More examples of specialization:
function ErrorAlert({ children }) {
return <Alert type="error" icon="!">{children}</Alert>;
}
function PageLayout({ children }) {
return <Layout sidebar={<Nav />} header={<Header />}>{children}</Layout>;
}
function AdminPage({ children }) {
return <PageLayout><RequireAuth role="admin">{children}</RequireAuth></PageLayout>;
}Each level adds specific behavior while delegating to the generic component underneath.
The containment pattern is when a component does not know its children ahead of time. It acts as a container and renders whatever children are passed to it.
function Card({ title, children }) {
return (
<div className="card">
<h3 className="card-title">{title}</h3>
<div className="card-body">{children}</div>
</div>
);
}
<Card title="User Profile">
<img src="avatar.png" alt="Avatar" />
<p>John Doe</p>
<p>john@example.com</p>
</Card>Sometimes you need multiple "slots" — different areas of a component that accept different content. While React does not have named slots like some other frameworks, you can achieve the same thing using regular props:
function Layout({ header, sidebar, children }) {
return (
<div className="layout">
<header className="layout-header">{header}</header>
<aside className="layout-sidebar">{sidebar}</aside>
<main className="layout-content">{children}</main>
</div>
);
}
// Usage:
<Layout
header={<NavBar />}
sidebar={<SideMenu items={menuItems} />}
>
<ArticleList articles={articles} />
</Layout>Any prop can accept JSX elements — not just children. This gives you the flexibility to create components with multiple injection points:
function Modal({ title, footer, children }) {
return (
<div className="modal-overlay">
<div className="modal">
<div className="modal-header">{title}</div>
<div className="modal-body">{children}</div>
<div className="modal-footer">{footer}</div>
</div>
</div>
);
}
<Modal
title={<h2>Confirm Delete</h2>}
footer={<><button>Cancel</button><button>Delete</button></>}
>
<p>Are you sure you want to delete this item?</p>
</Modal>A particularly powerful use of composition is layout components. These components define the visual structure of a page or section and let you fill in the content.
function SplitPane({ left, right }) {
return (
<div style={{ display: 'flex', gap: '16px' }}>
<div style={{ flex: 1 }}>{left}</div>
<div style={{ flex: 1 }}>{right}</div>
</div>
);
}
<SplitPane
left={<ContactList contacts={contacts} />}
right={<ChatWindow messages={messages} />}
/>Layout components are reusable across your entire application. Here are some common patterns:
// A centered container
function CenterContent({ maxWidth, children }) {
return (
<div style={{
maxWidth: maxWidth || '800px',
margin: '0 auto',
padding: '0 16px',
}}>
{children}
</div>
);
}
// A stack layout (vertical spacing)
function Stack({ gap, children }) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: gap || '8px' }}>
{children}
</div>
);
}
// Usage:
<CenterContent maxWidth="600px">
<Stack gap="16px">
<h1>Welcome</h1>
<p>This is centered and stacked.</p>
<Button>Get Started</Button>
</Stack>
</CenterContent>Best practices for composition:
<Card type="user" showAvatar showBio /> with many flags, compose smaller pieces: <Card><Avatar /><Bio /></Card>.<div id="root"></div>
<script src="https://unpkg.com/react@19/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@19/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Card({ title, children }) {
return (
<div style={{
border: '1px solid #ccc',
borderRadius: '8px',
padding: '16px',
marginBottom: '12px',
}}>
<h3 style={{ marginTop: 0 }}>{title}</h3>
<div>{children}</div>
</div>
);
}
function Badge({ color, children }) {
return (
<span style={{
backgroundColor: color,
color: 'white',
padding: '2px 8px',
borderRadius: '12px',
fontSize: '12px',
}}>
{children}
</span>
);
}
function App() {
return (
<div style={{ maxWidth: '400px', margin: '20px auto' }}>
<Card title="React Fundamentals">
<p>Learn the core concepts of React.</p>
<Badge color="green">Beginner</Badge>
</Card>
<Card title="Advanced Patterns">
<p>Composition, render props, and more.</p>
<Badge color="orange">Intermediate</Badge>
</Card>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>What is the 'children' prop in React?