Children and composition
HTML has always worked by nesting: a <select> wraps its <option>s, a <ul> wraps its <li>s, a <button> wraps its label. The element in the middle is a child of the element around it, and the two work together to make the thing you see. React components can work the same way. Instead of passing everything in through named props, a component can wrap around content the way native elements do, and that single idea is what separates a component you configure from a component you compose.
This chapter builds the argument the way the course does, through a Button for a component library: first children, then prop spreading, then the finishing touches that make a component reusable in practice.
Children as an interface
The Props chapter introduced children: content between a component's opening and closing tags arrives as a prop of that name. What it buys you for reuse is bigger than it looks.
function Button({ children }) {
return <button>{children}</button>
}
// usage: <Button>Buy now</Button>The component decides where the children render, and the caller decides what they are. Compare that with a text prop, which works until the caller wants anything beyond a string. With children, there's nothing stopping them from passing more than text:
// usage:
// <Button>
// <CartIcon />
// Buy now
// </Button>An icon to the left of the label, with no icon prop, no iconPosition="left" option, no anticipation from the component's author at all. Want the icon on the right? Move it to the other side of the text. Every configuration prop the author would have had to invent dissolves into the caller writing the markup they meant.
Forwarding the rest of the props
A Button that renders a native <button> has a second problem: events. When a caller writes <Button onClick={...}>, that onClick is a custom prop landing on your component; nothing happens unless the component passes it through to the real <button> underneath. You could forward onClick by hand, then onDoubleClick, then style, then className, and still never cover everything a native button accepts. The spread syntax forwards them all at once:
function Button({ children, ...rest }) {
return <button {...rest}>{children}</button>
}Destructure the props your component actually handles, collect everything else with rest syntax, and spread the rest onto the underlying element. Every valid button attribute the caller passes, event handlers included, lands where it belongs. Props your component invents for itself (a variant, say) get destructured out so they never reach the DOM element at all.
Making room for your own API
Reusable components usually add options on top of the native element. The course's button takes a size ("sm" or "lg") and a variant ("success", "warning", "danger"), each mapping to a CSS class:
function Button({ children, size, variant, className, ...rest }) {
const sizeClass = size ? `button-${size}` : ''
const variantClass = variant ? `button-${variant}` : ''
const allClasses = [sizeClass, variantClass, className].filter(Boolean).join(' ')
return (
<button className={allClasses} {...rest}>
{children}
</button>
)
}That merge avoids a subtle bug. If the component sets className and the caller also passes one, whichever lands last on the element wins: spread the rest after your own className and the caller's class silently overwrites yours; spread it before and yours overwrites theirs. Destructuring className out and merging the strings yourself is the fix. Libraries like clsx or classnames exist to do exactly this merge once the conditions multiply.
children doesn't need a text prop, an icon prop, and an icon-position prop. Whoever uses it writes the icon and text inside the tags in the order they want, and the Button drops that content wherever it belongs. Nesting, the thing HTML has always done, is also React's best trick for reuse.
Next up: Compound components, where one component becomes several that work together.

