Slots let you pass content (HTML, text, or components) from a parent into a child component, so you can create highly reusable, flexible UI components.
Let’s break them down step-by-step:
→ Default Slots
→ Named Slots
→ Scoped Slots
🧩 1. What Is a Slot?
A slot is a placeholder inside a component’s template where the parent can insert content.
You define a slot inside the child component, and fill it from the parent component.
🟢 2. Default Slot
The default slot is used when a component expects some content, but the slot isn’t given a name.
✅ Example
Card.vue (Child)
<template>
<div class="card">
<h3>Card Component</h3>
<slot></slot> <!-- default slot -->
</div>
</template>
<style scoped>
.card {
border: 1px solid #ccc;
padding: 10px;
border-radius: 8px;
}
</style>
App.vue (Parent)
<template>
<Card>
<p>This content comes from the parent!</p>
</Card>
</template>
<script setup>
import Card from './Card.vue'
</script>
🧠 Explanation:
- The
<slot></slot>inCard.vueis replaced by whatever content is placed between<Card>...</Card>in the parent. - If no slot content is provided, the slot is empty.
🟡 3. Default Slot with Fallback Content
You can provide default (fallback) content that appears if no slot content is passed.
✅ Example
<template>
<div class="card">
<slot>
<p>No content provided. This is default fallback text.</p>
</slot>
</div>
</template>
🟣 4. Named Slots
Sometimes a component has multiple content areas — e.g., header, body, footer.
You can name each slot to control where the parent’s content goes.
✅ Example
Card.vue (Child)
<template>
<div class="card">
<header>
<slot name="header">Default Header</slot>
</header>
<main>
<slot>Default Body</slot>
</main>
<footer>
<slot name="footer">Default Footer</slot>
</footer>
</div>
</template>
App.vue (Parent)
<template>
<Card>
<template #header>
<h2>📰 Custom Header</h2>
</template>
<p>This is the main content from the parent.</p>
<template #footer>
<button>Read More</button>
</template>
</Card>
</template>
<script setup>
import Card from './Card.vue'
</script>
🧠 Explanation:
- Use
<template #name>(orv-slot:name) to specify which slot to fill. - Unnamed content goes into the default slot.
🔵 5. Scoped Slots
Scoped slots let the child send data back up to the parent’s slot content.
It’s a way for a parent to “render” child content dynamically based on child data.
✅ Example
UserList.vue (Child)
<template>
<ul>
<li v-for="user in users" :key="user.id">
<!-- Provide data to the parent slot -->
<slot :user="user">{{ user.name }}</slot>
</li>
</ul>
</template>
<script setup>
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 }
]
</script>
App.vue (Parent)
<template>
<UserList>
<template #default="{ user }">
<strong>{{ user.name }}</strong> — <em>{{ user.age }} years old</em>
</template>
</UserList>
</template>
<script setup>
import UserList from './UserList.vue'
</script>
🧠 Explanation:
- The child (
UserList.vue) exposesuserto the slot via:user="user". - The parent can access that variable inside the slot template.
- It’s like passing props from child → parent’s slot content.
⚙️ 6. Scoped Slot Syntax Options
You can use v-slot (full syntax) or the shorthand #.
<!-- full syntax -->
<template v-slot:default="{ user }">
{{ user.name }}
</template>
<!-- shorthand -->
<template #default="{ user }">
{{ user.name }}
</template>
<!-- shorthand when using default slot -->
<UserList v-slot="{ user }">
{{ user.name }}
</UserList>
🧠 7. Combining Slots
You can mix default, named, and scoped slots easily.
Example:
<template>
<div class="profile-card">
<slot name="avatar"></slot>
<slot :user="user"></slot> <!-- scoped slot -->
</div>
</template>
<script setup>
const user = { name: 'Jane', role: 'Admin' }
</script>
Parent:
<ProfileCard>
<template #avatar>
<img src="avatar.jpg" width="50">
</template>
<template #default="{ user }">
<p>{{ user.name }} — {{ user.role }}</p>
</template>
</ProfileCard>
🧱 8. Summary Table
| Type | Use Case | Syntax in Child | Syntax in Parent |
|---|---|---|---|
| Default Slot | Insert content | <slot></slot> | <Child>content</Child> |
| Named Slot | Multiple sections | <slot name="header"> | <template #header> |
| Scoped Slot | Pass data from child to parent slot | <slot :user="user"> | <template #default="{ user }"> |
🎯 When to Use Each
- Default Slot → For basic, single-content components (e.g., cards, modals)
- Named Slots → For multi-section layouts (e.g., header/body/footer)
- Scoped Slots → For reusable lists/tables with flexible data rendering
