Slots
Props pass data into a child. Slots pass markup — letting a parent drop arbitrary template content inside a child component. This is Vue's direct equivalent of React's children (Fundamentals Chapter 9) and Angular's <ng-content>, and it's how you build flexible wrappers like cards, modals, and layouts that don't need to know what's placed inside them.
The Default Slot
The <slot></slot> element is a placeholder — whatever the parent writes between the component's opening and closing tags gets rendered there. Card doesn't know or care it's rendering an <h2> and a <p>; it just wraps whatever it's given. This is exactly React's {children}, just declared with a <slot> tag in the template rather than read as a prop.
Fallback (Default) Content
Content placed inside the <slot> tag is fallback content — shown only when the parent passes nothing. A small convenience React lacks built-in (you'd write {children ?? 'fallback'} by hand); in Vue it's just whatever you put between the slot tags.
Named Slots — Multiple Insertion Points
When a component needs several insertion points, give each <slot> a name. The parent targets a named slot with <template #header> (the # is shorthand for v-slot:header); anything not wrapped in a named template goes into the default slot. This is cleaner than React's approach for multi-region layouts, where you'd pass JSX through several separate named props (the SplitLayout pattern from React Fundamentals Chapter 9) — Vue keeps it all between one set of component tags.
Scoped Slots — Passing Data Back to the Slot Content
A scoped slot lets the child pass data up to the markup the parent provides — the child binds values onto its <slot> (:todo="todo"), and the parent receives them by destructuring in v-slot (#default="{ todo }"). This is the powerful case: TodoList owns the looping and data, but the parent decides exactly how each item looks. It's the direct equivalent of React's render-props pattern (Advanced Chapter 5) — "the component owns behavior, the caller controls rendering" — but expressed declaratively in the template.
children for simple content, named props for multi-region layouts, and the render-props pattern for "expose data to the caller's markup." Vue's slot system handles all three with one consistent mechanism: default slot, named slots, and scoped slots. If render props felt clunky in React, scoped slots are the cleaner, template-native version of the same idea.
| Vue | React | Angular |
|---|---|---|
| <slot> (default) | {children} | <ng-content> |
| Named slots (#header) | Named JSX props | <ng-content select="..."> |
| Scoped slots | Render props | Structural directive / template context |
| Fallback in <slot> | Manual children ?? fallback | Default ng-content content |
Coding Challenges
Build a Card component with a default slot wrapped in a styled div, then use it twice in a parent with completely different inner markup (a heading vs an image + caption). Add fallback slot text shown when no content is passed.
📄 View solutionBuild a Panel component with named header and footer slots plus a default slot for the body, and fill all three from a parent using <template #header> / default content / <template #footer>.
📄 View solutionBuild a List component that takes an items array prop, loops over it, and exposes each item to a scoped slot (:item="item"). In the parent, use v-slot to render each item your own way (e.g. bold name + muted id).
📄 View solutionChapter 8 Quick Reference
- <slot></slot> — placeholder for parent-provided markup (= React's
children) - Content inside the
<slot>tag is fallback, shown when the parent passes nothing - Named slots (
<slot name="header">) — multiple insertion points; parent targets with#header - Scoped slots — child binds data onto
<slot :x="x">; parent receives via#default="{ x }"(= render props) - Rule of thumb: props for values, slots for markup
- One slot mechanism covers what React split across children, named props, and render props
- Next chapter: lifecycle hooks — onMounted, onUnmounted, and friends