All topics
Patternsbeginner

Composition over Inheritance

Understand why React favors composing components together rather than building class hierarchies to share behavior.

React's official guidance is explicit: use composition, not inheritance, to reuse code between components. Unlike some UI frameworks that encourage subclassing a base component to add or override behavior, React components share behavior by being composed together — one component rendering another, or accepting other components/elements via props (including the special children prop).

Composition is like building with modular furniture pieces you can rearrange in any room, while inheritance is like a custom-built cabinet permanently fixed to one wall — the modular pieces adapt naturally as your needs change, while the fixed cabinet requires real carpentry work to modify.

Key Concepts

1
This fits naturally with function components, which don't have a meaningful inheritance story the way classes do (you generally wouldn't write class SpecialButton extends Button). Instead, variation is expressed by parameterizing a component with props, or by explicitly wrapping/combining components — for example, a FancyBorder component that renders whatever children it's given inside a styled wrapper, rather than a Panel class extending a Border class.
class SpecialButton extends ButtonFancyBorderchildrenPanelBorder
2
When different components need to share non-visual logic (not markup structure), the answer is a custom hook, not a shared base class — hooks let you compose *behavior* the same way component composition lets you compose *markup*. Between props-based specialization, the children prop for slotting arbitrary content, and custom hooks for behavior, React rarely has a good reason to reach for class inheritance at all.
3
Interviewers ask candidates to explain why React explicitly avoids encouraging component inheritance hierarchies, expecting an answer that touches on flexibility (composition adapts to many shapes of reuse) and the fact that inheritance chains tend to become rigid and hard to refactor as an app's needs evolve.