What are slots?

Slots are Vue’s mechanism for transferring template content to components. They allow you to create flexible, reusable components with dynamic content.
Basic Slots
Parent component:
<template>
<Card>
<p>This content will be included in the slot</p>
</Card>
</template>
<script setup>
import Card from './Card.vue'
</script>
The Card.vue component:
<template>
<div class="card">
<div class="card-header">
<h3>Card title</h3>
</div>
<!-- The content will be inserted here -->
<slot></slot>
</div>
</template>
Named slots
Parent component:
<template>
<Layout>
<template v-slot:header>
<h1>My headline</h1>
</template>
<template v-slot:default>
<p>Main content</p>
</template>
<template v-slot:footer>
<p>© 2023 My Website</p>
</template>
</Layout>
</template>
The Layout.vue component:
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- default slot -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
Scoped Slots (Slots with data)
The List.vue component:
<template>
<ul>
<li v-for="(item, index) in items" :key="index">
<!-- Passing the item data to the slot -->
<slot :item="item" :index="index"></slot>
</li>
</ul>
</template>
<script setup>
defineProps<{
type: string[];
}>();
</script>
Parent component:
<template>
<List :items="users">
<!-- We receive data through the v-slot -->
<template v-slot="{ item, index }">
<p>{{ index + 1 }}. {{ item.name }} ({{ item.age }})</p>
</template>
</List>
</template>
<script setup>
import List from './List.vue'
const users = [
{ name: 'Alex', age: 28 },
{ name: 'Bob', age: 24 }
]
</script>
Dynamic slot names
<template>
<DynamicSlot>
<template v-slot:[dynamicSlotName]>
Content for the dynamic slot
</template>
</DynamicSlot>
</template>
<script setup>
import { ref } from 'vue'
import DynamicSlot from './DynamicSlot.vue'
const dynamicSlotName = ref('header')
</script>
Practical tips
- Abbreviated syntax: v-slot:header → #header
- Fallback content: default content can be set
<slot>Backup content if nothing is transmitted</slot>
Conclusion
- Regular slots — for basic content
- Named slots — for precise positioning
- Scoped slots — for transferring data to the parent component
- Dynamic slots — for flexible scenarios
Homework assignment
- Create a Tabs component using slots
- Implement the DataTable component with scoped slots for custom row display
- Experiment with dynamic slot names
<!-- Example of Tabs.vue -->
<template>
<div class="tabs">
<div class="tab-header">
<slot name="header"></slot>
</div>
<div class="tab-content">
<slot></slot>
</div>
</div>
</template>