Component Composition
Composition is how React builds complexity from simplicity. Instead of one large component that does everything, you build many small components and compose them together. Each layer adds one piece of behavior or structure.
The children prop
Section titled “The children prop”React passes any JSX placed between a component’s opening and closing tags as a special children prop:
function Card({ children }) { return ( <div className="card"> {children} </div> );}Now Card is a reusable wrapper. You decide what goes inside at the call site:
<Card> <h2>Income</h2> <p>$4,300 this month</p></Card>
<Card> <h2>Housing</h2> <p>$1,200 budgeted</p></Card>Both render a card-styled wrapper with different content. The Card component does not need to know what it wraps — that is the caller’s decision.
Composing ZeroBudget’s layout
Section titled “Composing ZeroBudget’s layout”The top section of ZeroBudget has two parts side by side: the income panel and the left-to-assign number. In App.jsx:
function App() { return ( <div className="app"> <header className="app-header"> <h1>ZeroBudget</h1> </header> <main className="app-main"> <MonthNav /> <div className="app-top"> <IncomeSection incomeSources={sources} /> <LeftToAssign amount={leftToAssign} /> </div> <section className="categories-section"> {categories.map(cat => ( <CategoryCard key={cat.id} category={cat} /> ))} </section> </main> </div> );}App orchestrates layout. Each child component handles its own content. No single component is responsible for everything.
Passing extra props
Section titled “Passing extra props”Sometimes you want to compose by spreading props through:
function LabeledInput({ label, ...inputProps }) { return ( <div className="field"> <label>{label}</label> <input {...inputProps} /> </div> );}
<LabeledInput label="Amount" type="number" placeholder="0.00" step="0.01" />...inputProps collects all remaining props and spreads them onto the <input>. The LabeledInput component does not need to list every possible input attribute — it just passes them through.
Composition vs inheritance
Section titled “Composition vs inheritance”Coming from object-oriented languages, you might reach for inheritance to share behavior between components. React explicitly recommends composition instead. Components share behavior by accepting and using other components, not by extending them.
If two components share logic (not UI), extract the logic into a custom hook (covered in Module 06). If they share UI structure, extract it into a shared component that accepts children.
Exercise
Section titled “Exercise”- Create a
Cardcomponent insrc/components/Card/Card.jsxthat wraps itschildrenin a<div className="card">. - Update
IncomeSectionto use<Card>as its outer wrapper instead of a plain<section>. - Create a placeholder
CategoryCardcomponent that also uses<Card>. Pass acategoryprop with anameproperty and render the name inside the card. - Render three
CategoryCardcomponents inApp.jsxusing a hardcoded categories array.
- Composition builds complex UIs from small, focused components.
- The
childrenprop holds any JSX passed between a component’s opening and closing tags. - Spread remaining props with
...restto create pass-through wrapper components. - Prefer composition over inheritance — share UI structure with
children, share logic with custom hooks.