Slots
Introduction
Slots let parent components inject content into child templates—like props for markup instead of data. Use default slots for simple wrappers, named slots for layouts, and scoped slots when the child exposes data back to the parent’s template.
Prerequisites
Default Slot
BaseCard.vue:
Parent fills the slot:
<BaseCard>
<h2>Title</h2>
<p>Body text from parent.</p>
</BaseCard>Code explanation:
- Content between tags goes into
<slot> - Fallback text renders only when parent provides no content
Explicit default slot syntax:
<BaseCard>
<template #default>
<p>Default slot content</p>
</template>
</BaseCard>Named Slots
PageLayout.vue:
Parent:
<PageLayout>
<template #header>
<h1>Dashboard</h1>
</template>
<p>Main content here.</p>
<template #footer>
<small>© 2026 Hello Code</small>
</template>
</PageLayout>Shorthand #header = v-slot:header.
Scoped Slots (Slot Props)
Child exposes data to slot content:
TodoList.vue:
Parent customizes each row:
<TodoList :todos="todos">
<template #item="{ todo, index }">
<label>
<input type="checkbox" :checked="todo.done" />
{{ index }}. {{ todo.text }}
</label>
</template>
</TodoList>Code explanation:
{ todo, index }destructures slot props- Default slot content inside child used when parent omits
#item
Renderless Pattern (Concept)
Component provides logic via scoped slot, minimal markup:
<MouseTracker v-slot="{ x, y }">
<p>Mouse at {{ x }}, {{ y }}</p>
</MouseTracker>Similar idea to composables—Composables often replace renderless components today.
Multiple Named Slots + Layout
AppShell.vue for admin UIs:
<template>
<div class="shell">
<aside class="shell__sidebar">
<slot name="sidebar" />
</aside>
<div class="shell__body">
<slot name="toolbar" />
<slot />
</div>
</div>
</template>Pairs with Router views later—layout wraps <RouterView />.
slot vs props
| Props | Slots | |
|---|---|---|
| Pass | Data, objects, functions | HTML / components |
| Flexibility | Fixed shape | Parent controls markup |
| Use | Configuration | Layout, customization |
Pass data as props; pass structure as slots.
Conditional Slot Content
Parent can gate slot content with v-if:
<BaseCard>
<template v-if="loggedIn" #header>
Welcome back
</template>
</BaseCard>Practice: Media Object
Build MediaObject.vue:
- Named slots:
media,body, optionalactions - Scoped slot
#body="{ title, subtitle }"from child props (child passes strings into slot props)
Use for comment list or notification row.
FAQ
slot vs children in React?
Conceptually similar—Vue makes named/scoped slots explicit.
Can I slot into component root?
Yes—slot content compiles in parent scope (access parent data).
Scoped slot prop naming?
Any names on <slot :todo="todo">—destructure in parent #item="{ todo }".
Default slot + named slots?
Unnamed content goes to default <slot /> without name.
v-slot on component?
<MyComp v-slot="props"> when single default scoped slot.
Empty slot fallback?
Put default content inside <slot>...</slot> in child.