Slots, Composition, and the Shape of a Safe Override
Material UI’s Button case showed how a style decision travels through a component. The harder adaptation begins when the desired change is structural: a different root element, a custom interior part, a router link, or a component that must receive a ref. This chapter explains the slot model and the composition contracts around it, so that a reader can choose the right replacement point without confusing a DOM change with a harmless visual override.
A Component Is a Tree of Contracts
A Material UI component is best understood as a rendered tree with named responsibilities. The outermost element is the root slot. It is the component’s primary node in the DOM and the place where the component’s main styles and behavior meet. More complex components contain interior slots as well: a list may have a listbox and items, an autocomplete may have an input, popup, and indicators, and a custom component may divide its content into a root, value, and unit.
The slot names are useful because they give structure a stable vocabulary. Without them, an application would have to target whatever DOM happens to be emitted today. With them, the application can say which part it wants to replace or configure. The goal is not to expose every implementation detail. It is to expose the structural parts that an application has a legitimate reason to adapt.
The distinction between root and interior slots determines which API should be used. The component prop changes the root element or supplies another component to fill that root. It is appropriate when the outer element needs to change but the existing slot’s styling and behavior should remain. A Button that should behave as a link is a direct example: the root can become an anchor or a router link while the Button’s visual contract remains in place.
The slots prop is broader. It replaces the implementation assigned to a named slot, including the root when that is the intended boundary. This is the choice when the application needs to change a slot’s styling or functionality rather than only the element used to fill it. slotProps is narrower in a different direction: it keeps the slot implementation but supplies additional props to it. A caller might add an attribute to an interior slot, change a popper’s placement, or pass a callback that derives slot props from the component’s ownerState.
These options can look interchangeable in a short example, but they preserve different parts of the contract. Use component when the element must change and the existing slot behavior is still wanted. Use slots when the slot’s implementation itself must be replaced. Use slotProps when the implementation should remain but needs additional input. The choice tells future readers which part of the component the application considers replaceable.