Vue v-slot Directive
Modern syntax for working with named and scoped slots
🎯 What is v-slot?
The v-slot directive is the modern way to define slot content in Vue. It provides a unified syntax for named slots and scoped slots, making your code cleaner and more readable than the old slot syntax.
<!-- Modern v-slot syntax -->
<Card>
<template v-slot:header>
<h2>Title</h2>
</template>
</Card>
<!-- Shorthand -->
<Card>
<template #header>
<h2>Title</h2>
</template>
</Card>
v-slot Features
Named Slots
Target specific slot locations
<template v-slot:header>
Content
</template>
Shorthand Syntax
Use # for cleaner code
<template #header>
Content
</template>
Scoped Slots
Access child component data
<template #default="slotProps">
{{ slotProps.item }}
</template>
Destructuring
Extract specific properties
<template #default="{ item }">
{{ item }}
</template>
🔹 Basic v-slot Usage
Use v-slot to target named slots:
🔸 Child Component (Layout.vue)
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
🔸 Parent Component
<template>
<Layout>
<template v-slot:header>
<h1>My Website</h1>
</template>
<p>Main content here</p>
<template v-slot:footer>
<p>© 2025 My Company</p>
</template>
</Layout>
</template>
Output:
🔹 Shorthand Syntax (#)
Use the # symbol as shorthand for v-slot:
<template>
<Card>
<!-- Full syntax -->
<template v-slot:header>
<h2>Full Syntax</h2>
</template>
<!-- Shorthand (recommended) -->
<template #title>
<h3>Shorthand Syntax</h3>
</template>
<!-- Default slot -->
<template #default>
<p>Content</p>
</template>
</Card>
</template>
Best Practice: Use the # shorthand for cleaner, more readable code.
🔹 Default Slot with v-slot
Target the default (unnamed) slot:
<template>
<Container>
<!-- Method 1: Direct content (no template) -->
<p>This goes to default slot</p>
<!-- Method 2: Explicit default slot -->
<template #default>
<p>Explicit default slot</p>
</template>
</Container>
</template>
🔹 v-slot with Scoped Slots
Access data from child component:
<!-- Child Component (UserList.vue) -->
<template>
<div>
<div v-for="user in users" :key="user.id">
<slot :user="user" :index="index"></slot>
</div>
</div>
</template>
<!-- Parent Component -->
<template>
<UserList>
<template #default="slotProps">
<p>{{ slotProps.user.name }}</p>
</template>
</UserList>
</template>
🔹 Destructuring Slot Props
Extract specific properties from slot props:
<template>
<TodoList>
<!-- Destructure the slot props -->
<template #default="{ item, index, remove }">
<div>
<span>{{ index + 1 }}. {{ item.text }}</span>
<button @click="remove(item.id)">Delete</button>
</div>
</template>
</TodoList>
</template>
Tip: Destructuring makes your code cleaner by directly accessing the properties you need.
🔹 Multiple Named Slots with v-slot
Combine multiple named slots in one component:
<template>
<Modal>
<template #header>
<h2>Confirm Action</h2>
</template>
<template #body>
<p>Are you sure you want to proceed?</p>
</template>
<template #footer>
<button>Cancel</button>
<button>Confirm</button>
</template>
</Modal>
</template>
🔹 Dynamic Slot Names
Use dynamic slot names with v-slot:
<template>
<Component>
<template v-slot:[dynamicSlotName]>
<p>Dynamic slot content</p>
</template>
<!-- Shorthand -->
<template #[dynamicSlotName]>
<p>Dynamic slot content</p>
</template>
</Component>
</template>
<script setup>
import { ref } from 'vue'
const dynamicSlotName = ref('header')
</script>