How to use slots in Vue
Vue slots enable flexible component composition by allowing parent components to pass content into specific areas of child components. Slots act as placeholders that can be filled with custom content, making components more reusable and flexible. They’re essential for building layout components, modals, cards, and any component that needs customizable content areas.
Use <slot></slot>
in child components and pass content from parent components for flexible composition.
<!-- Button.vue - Child component with slot -->
<template>
<button class="btn" :class="variant">
<slot>Default Text</slot>
</button>
</template>
<script>
export default {
props: {
variant: {
type: String,
default: 'primary'
}
}
}
</script>
<!-- Layout.vue - Named slots -->
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- default slot -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- ItemList.vue - Scoped slots -->
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot :item="item" :index="item.id">
{{ item.name }}
</slot>
</li>
</ul>
</template>
<script>
export default {
props: ['items']
}
</script>
<!-- Parent.vue - Using slots -->
<template>
<div>
<!-- Basic slot usage -->
<Button>Click Me</Button>
<Button variant="danger">Delete</Button>
<!-- Named slots -->
<Layout>
<template #header>
<h1>My App</h1>
</template>
<p>Main content here</p>
<template #footer>
<p>© 2025 CoreUI</p>
</template>
</Layout>
<!-- Scoped slots -->
<ItemList :items="products">
<template #default="{ item, index }">
<div class="product">
<h3>{{ item.name }}</h3>
<p>${{ item.price }}</p>
<span>Item #{{ index }}</span>
</div>
</template>
</ItemList>
</div>
</template>
<script>
import Button from './Button.vue'
import Layout from './Layout.vue'
import ItemList from './ItemList.vue'
export default {
components: { Button, Layout, ItemList },
data() {
return {
products: [
{ id: 1, name: 'Product A', price: 29.99 },
{ id: 2, name: 'Product B', price: 39.99 }
]
}
}
}
</script>
Vue slots work with three main types: default slots for basic content insertion, named slots for multiple content areas using v-slot:name
or #name
, and scoped slots that pass data from child to parent using slot props. Default slots provide fallback content when no content is passed. Named slots allow multiple content areas in one component. Scoped slots enable child components to share data with parent slot content. Use $slots.slotName
to conditionally render slot containers.
Best Practice Note:
This is the same slot approach used in CoreUI Vue components for maximum flexibility. Use descriptive slot names, provide fallback content for better UX, leverage scoped slots for data sharing, check slot existence with $slots before rendering containers, and document slot APIs for team collaboration and component reusability.