Slots in Vue provide a flexible way to inject content from a parent component into predefined locatinos within a child component. This mechanism enables reusable, composable components while maintaining clear separation of concerns—especially when content structure is determined externally but rendered inside a dedicated UI shell.
Core Slot Types
Vue supports three primary slot types: default, named, and scoped—each serving distinct composition patterns.
Default Slot
In the child component, a single unnamed <slot> serves as the fallback container:
<template>
<section class="card">
<header><slot>Default header content</slot></header>
<main><slot>Default body content</slot></main>
</section>
</template>
The parent supplies content without naming:
<Card>
<h2>Custom Title</h2>
<p>This replaces both slots due to implicit fallback behavior.</p>
</Card>
Named Slots
When multiple insertion points exist, use the name attribute on <slot> and v-slot (or its sohrthand #) on the parent side:
<!-- Child component -->
<template>
<article>
<header><slot name="header">Default header</slot></header>
<footer><slot name="footer">Default footer</slot></footer>
</article>
</template>
<!-- Parent usage -->
<Card>
<template #header>
<h1>Main Heading</h1>
</template>
<template #footer>
<small>© 2024</small>
</template>
</Card>
Scoped Slots (Dynamic Content Rendering)
Scoped slots pass data from the child to the parent, enabling external control over how internal state is rendered. The child exposes reactive properties via slot props:
<!-- Child: GameList.vue -->
<template>
<div class="game-grid">
<slot
:items="availableGames"
:count="availableGames.length"
:isEmpty="availableGames.length === 0"
>
</slot>
</div>
</template>
<script>
export default {
name: 'GameList',
data() {
return {
availableGames: ['StarCraft', 'Doom', 'Tetris', 'Pac-Man']
}
}
}
</script>
The parent receives these values as an object and may destructure them directly:
<!-- Parent -->
<GameList>
<template #default="{ items, count }">
<ol>
<li v-for="(game, index) in items" :key="index">
{{ index + 1 }}. {{ game }}
</li>
</ol>
<p>Total: {{ count }} games</p>
</template>
</GameList>
For brevity, shorthand syntax is supported:
<GameList v-slot="{ items }">
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</GameList>
Note: In Vue 3, v-slot is the only supported directive for defining slots; legacy attributes like slot and slot-scope are removed.