props.children is a special prop in React that allows you to pass content (JSX, text, components) BETWEEN the opening and closing tags of a component. It's like a placeholder for whatever you put inside the component.
// Normal props (passed as attributes)
<Car name="Audi" color="blue" />
// props.children (passed between tags)
<Card>
<p>This content becomes props.children</p>
</Card>// In Component.jsx
export function Card(props) {
return (
<div className="card-container">
<div className="card-content">
{props.children}
</div>
</div>
);
}
// With destructuring (cleaner)
export function Card({ children }) {
return (
<div className="card-container">
<div className="card-content">
{children}
</div>
</div>
);
}<Card>
<h2>Welcome!</h2>
<p>This is inside the card</p>
</Card>
<Card>
<Student />
</Card>
<Card>
Any content here becomes children!
</Card>export function Button({ children, onClick }) {
return (
<button onClick={onClick} className="custom-button">
{children}
</button>
);
}// Simple text
<Button onClick={validateNumber}>
VALIDATE ME
</Button>
// Text with icon
<Button onClick={validateNumber}>
✓ VALIDATE ME
</Button>
// Multiple elements
<Button onClick={validateNumber}>
<span>🚀</span>
<span>Click Here</span>
</Button>export function Section({ title, children }) {
return (
<div className="section-container">
<h2>{title}</h2>
<div className="section-body">
{children}
</div>
</div>
);
}<Section title="Vehicle Information">
<Vehicle brands={vehicleBrands} info={vehicleInfo} />
</Section>
<Section title="Fruits Collection">
<Fruits fruits={myFruitList} fruitDetails={myFruitDetails} />
</Section>
<Section title="Validation Tool">
<input type="number" />
<button>Validate</button>
</Section>export function Alert({ type, children }) {
return (
<div className={`alert alert-${type}`}>
<span className="alert-icon">
{type === 'success' ? '✓' : '⚠'}
</span>
<div className="alert-message">
{children}
</div>
</div>
);
}<Alert type="success">
<p>Number is valid, Thanks!</p>
</Alert>
<Alert type="error">
<p>Number is not valid</p>
<p>Please enter a number between 1-10</p>
</Alert>Before (without props.children):
// App.jsx
return (
<>
<Navbar />
<Car name="Audi" color="blue" model="V8x" engine="H200p" price="$2000000"/>
<Student />
<Countries country={continent}/>
</>
);After (with props.children):
// Component.jsx
export function Layout({ children }) {
return (
<>
<Navbar />
<div className="main-content">
{children}
</div>
<Footer />
</>
);
}
// App.jsx
return (
<Layout>
<Car name="Audi" color="blue" model="V8x" engine="H200p" price="$2000000"/>
<Student />
<Countries country={continent}/>
</Layout>
);export function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<button className="modal-close" onClick={onClose}>×</button>
{children}
</div>
</div>
);
}const [showModal, setShowModal] = useState(false);
<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
<h2>Validation Result</h2>
<p>{text}</p>
<button onClick={() => setShowModal(false)}>Close</button>
</Modal>// In Component.jsx
export function Card({ title, children }) {
return (
<div className="card-wrapper">
{title && <h2 className="card-title">{title}</h2>}
<div className="card-body">
{children}
</div>
</div>
);
}<Card title="Car Information">
<Car name="Audi" color="blue" model="V8x" engine="H200p" price="$2000000"/>
</Card>
<Card title="Student Details">
<Student />
</Card>
<Card title="Number Validator">
<input
type="number"
className="number-input"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={validateNumber}>VALIDATE ME</button>
<p>{text}</p>
</Card>// Passed as attributes
<Car name="Audi" color="blue" />
// Accessed in component
function Car(props) {
return <p>{props.name}</p>
}// Passed between tags
<Card>
<p>Content here</p>
</Card>
// Accessed in component
function Card(props) {
return <div>{props.children}</div>
}✅ Use props.children when:
- Creating wrapper/container components (Card, Modal, Layout)
- Building reusable UI patterns (Button, Alert, Badge)
- You want flexible content inside a component
- Creating layout components (Header, Sidebar, Footer)
❌ Don't use props.children when:
- You need specific, named data (use regular props)
- You need to validate or transform the content
- The component has a fixed structure
- Flexibility: Can pass any content (text, JSX, components)
- Reusability: Same wrapper for different content
- Composition: Build complex UIs from simple components
- Cleaner Code: More readable than passing JSX as props
// In Component.jsx
export function InfoBox({ title, color, children }) {
return (
<div className="info-box" style={{ borderLeft: `4px solid ${color}` }}>
<h3>{title}</h3>
<div className="info-content">
{children}
</div>
</div>
);
}<InfoBox title="Vehicle Brands" color="#667eea">
<p>Available brands:</p>
<ul>
<li>{vehicleBrands[0]}</li>
<li>{vehicleBrands[1]}</li>
<li>{vehicleBrands[2]}</li>
</ul>
</InfoBox>
<InfoBox title="Validation Status" color="#f5576c">
{text ? <p>{text}</p> : <p>Enter a number to validate</p>}
</InfoBox>props.children is like a slot or placeholder:
- Whatever you put between
<Component>and</Component>becomesprops.children - It makes components flexible and reusable
- Perfect for wrappers, layouts, and containers
- Use destructuring:
function Card({ children })for cleaner code
Think of it this way:
- Regular props = specific data you pass TO a component
- props.children = content you pass INSIDE a component