A single children prop gives a component one content area, but real layouts often need several distinct, named regions — a header, body, and footer. This lesson covers implementing the Slot Pattern with named JSX props, the children-filtering alternative, and providing sensible slot defaults.
1Named Regions, Not Just One children Slot
A component with only a children prop provides a single content area, but layouts like a Card often need several distinct, independently positioned regions — a header, body, and footer. The Slot Pattern is about explicitly defining and filling multiple such named regions cleanly.
2Approach 1: Named Props Holding JSX
The most direct implementation accepts several props, each expecting a piece of JSX, placing each one in its designated spot within the component's layout. This approach is explicit, easy to type in TypeScript, and immediately clear at the call site.
3Approach 2: Filtering children by Sub-Component Type
An alternative nests slot markers as children of the parent — such as <Card.Header> and <Card.Body> — with the parent inspecting its children array and sorting each into the correct region based on component type. This reads more like natural JSX nesting, at the cost of more complex and fragile internal logic.
4Which Approach Should You Pick?
Named props holding JSX are simpler to implement, easier to type correctly, and explicit at the call site, making them the safer default recommendation. Children-filtering feels more natural to consumers accustomed to plain JSX nesting but introduces real fragility around unexpected element types being passed in.
5Slots with Fallback Defaults
A well-designed slot component provides sensible defaults for its optional slots via destructuring default values, so consumers only need to supply the specific regions they actually want to customize, falling back to a reasonable built-in default otherwise.
6Step-by-Step Breakdown
Named Regions, Not Just One children Slot. A Card with just children gives you one content area. But a real card layout often needs distinct, named regions — a header, a body, and a footer — each styled and positioned differently. The Slot Pattern is about explicitly defining and filling multiple such regions, cleanly.
Approach 1: Named Props Holding JSX. The simplest way to implement slots: accept several props, each expecting a piece of JSX, and place each one in its designated spot inside the layout. This is explicit, type-friendly (each slot can have its own required/optional typing), and easy to understand at a glance.
What's a key benefit of the named-props slot approach (<Card header={} body={} footer={} />) over a single children prop?
- →Each named slot can be independently positioned, styled, and even typed
- →It always requires writing less JSX overall
Approach 2: Filtering children by Sub-Component Type. An alternative approach nests slot markers as children — <Card><Card.Header>...</Card.Header><Card.Body>...</Card.Body></Card> — and the parent inspects children, sorting each child into the right region based on which sub-component it is. This reads more like natural JSX nesting, at the cost of more complex internal logic.
Which Approach Should You Pick?. Named props holding JSX are simpler to implement, easier to type in TypeScript, and explicit at the call site — they're the right default. Filtering children by type feels more natural for consumers used to plain JSX nesting, but adds real implementation complexity and fragility (what happens if a consumer passes an unexpected element type?).
Slots with Fallback Defaults. A well-designed slot component provides sensible defaults for optional slots, so consumers only need to fill in the ones they actually want to customize. Destructuring with a default value handles this cleanly: footer = <DefaultFooter />.
Mastery Achieved. You now understand the Slot Pattern: defining multiple named content regions with props holding JSX (the safer default), the alternative of filtering children by sub-component type, and providing sensible fallback defaults for optional slots. This closes out Advanced Component Patterns — next, you'll move into Advanced Data Fetching, starting with the Fetch API.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Named Slots Help Enforce Correct Semantic Structure
A Card component that explicitly wraps its header slot in a heading-appropriate element internally guarantees consistent semantic markup across every usage, rather than leaving heading level correctness entirely up to each consumer.
SEO Implications
- 1
Consistent Slot Structure Supports Predictable, Crawlable Markup
Because the component controls the surrounding structural markup (like which slot maps to which semantic HTML element), content across many pages using the same slot-based component stays structurally consistent, which benefits crawlers parsing repeated page patterns.
Best Practices
Default to Named Props for New Slot-Based Components
Unless there's a specific reason children-filtering reads meaningfully better for a particular component, named props holding JSX are simpler, safer, and easier to type correctly.
Give Every Optional Slot a Sensible Default
A slot that renders nothing when omitted can look like a bug; provide a reasonable default (or explicitly document that omitting it is intentional) so consumers aren't surprised by empty regions.
Frequent Bugs
A children-filtering slot component silently drops content because a consumer passed an unexpected element type as a child.
Add explicit handling (a fallback slot, a console warning, or a thrown error in development) for children that don't match any recognized sub-component type, rather than silently ignoring them.
An optional slot renders nothing and looks broken when a consumer simply doesn't need that region.
Provide a sensible default value for the slot prop via destructuring, or explicitly document that omitting the prop is a supported, intentional way to hide that region.
Real-World Examples
A Reusable Page Layout with Named Slots
A PageLayout component needs a consistent header, an optional sidebar, and a main content area used across many different pages. Implementing it with header, sidebar, and children props (sidebar defaulting to null when omitted) let every page compose its own content while sharing the same consistent structural layout.
function PageLayout({ header, sidebar = null, children }) {
return (
<div className="layout">
<header>{header}</header>
<div className="layout-body">
{sidebar && <aside>{sidebar}</aside>}
<main>{children}</main>
</div>
</div>
);
}