Containment

Some components cannot know their children ahead of time. A dialog, a card, a sidebar, a layout shell: each is a box with behavior and styling, and the contents are the caller's business. Such components use the children prop from The children Prop and render it as a hole in their own output.

One hole is rarely enough. A layout has a left and a right; a dialog has a body and a set of actions. Because JSX elements are ordinary values, you can pass them through any prop you like, which gives you named slots with no API beyond props.

One anonymous hole and two named onesJavaScript
const FancyBorder = ({ children }) =>            // fills the hole between the tags
  <div className="FancyBorder">{children}</div>;
const SplitPane = ({ left, right }) =>           // two named slots, placed by the container
  <div className="SplitPane">
    <div className="pane">{left}</div>
    <div className="pane">{right}</div>
  </div>;
const App = () => (
  <FancyBorder>
    <h3>Welcome</h3>
    <SplitPane left={<Contacts />} right={<Chat />} />
  </FancyBorder>
);

The left and right props are not strings or configuration objects but real React 7,897 elements, already created and waiting to be placed; pass null to leave a slot empty, or an array to fill one with several.

One subtlety: a slot element is rendered where the container puts it but was created in the caller, so it closes over the caller's variables and reads context from the caller's position in the tree.